diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6e81755..cfd9699 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,10 +1,10 @@ [bumpversion] -current_version = 3, 2, 0, 'final', 0 +current_version = 4, 0, 0, "alpha", 27 commit = False tag = False -parse = (?P\d+)\,\ (?P\d+)\,\ (?P\d+)\,\ \'(?P\S+)\'\,\ (?P\d+) +parse = (?P\d+)\,\ (?P\d+)\,\ (?P\d+)\,\ \"(?P\S+)\"\,\ (?P\d+) serialize = - {major}, {minor}, {patch}, '{release}', {build} + {major}, {minor}, {patch}, "{release}", {build} [bumpversion:part:release] optional_value = final diff --git a/.eslintignore b/.eslintignore index 713a2a5..74d8696 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 efff8c0..c332475 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,24 +7,41 @@ module.exports = { 'jest/globals': true }, globals: { - JSX: 'readonly' + BigInt: 'readonly', + HTMLCollectionOf: 'readonly', + JSX: 'readonly', + NodeJS: 'readonly', + RequestInit: 'readonly', + RequestInfo: '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' - }, - 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 +55,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 +67,85 @@ 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__', + 'allow_stdin', + 'allowed_extensions', + 'allowed_extensions_uris', + 'blocked_extensions', + 'blocked_extensions_uris', + 'bundles_extension', + 'cell_type', + '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', + 'implementation_version', + 'installed_version', + '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', + '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', 'no-control-regex': 'warn', diff --git a/.eslintrc.typecheck.js b/.eslintrc.typecheck.js new file mode 100644 index 0000000..a0890d9 --- /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/.flake8 b/.flake8 new file mode 100644 index 0000000..85402c1 --- /dev/null +++ b/.flake8 @@ -0,0 +1,16 @@ +[flake8] +ignore = E501, W503, E402 +builtins = c, get_config +exclude = + .cache, + .github, + docs, +enable-extensions = G +extend-ignore = + G001, G002, G004, G200, G201, G202, + # black adds spaces around ':' + E203, +per-file-ignores = + # B011: Do not call assert False since python -O removes these calls + # F841 local variable 'foo' is assigned to but never used + tests/*: B011, F841 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..4d23fdd --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# 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 3a04899..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve ---- - - - -## Description - - - -## Reproduce - - - -1. Go to '...' -2. Click on '...' -3. Scroll down to '...' -4. 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 4ed13c2..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,34 +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 635a80d..428c924 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 0000000..f10a5bc --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + # Set update schedule for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "weekly" diff --git a/.github/jupyterlab-probot.yml b/.github/jupyterlab-probot.yml new file mode 100644 index 0000000..ed61bdb --- /dev/null +++ b/.github/jupyterlab-probot.yml @@ -0,0 +1,3 @@ +binderUrlSuffix: "?urlpath=lab-dev" +addBinderLink: true +triageLabel: "status:Needs Triage" diff --git a/.github/labeler.yml b/.github/labeler.yml index 37f5778..11b00b4 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -5,6 +5,8 @@ Design System CSS: documentation: - docs/**/* - docs/* + - '*.md' + - '**/*.md' tag:CSS: - '**/*.css' @@ -44,6 +46,12 @@ pkg:attachments: - packages/attachments/**/* - packages/attachments/* +pkg:cell-toolbar: + - packages/cell-toolbar/**/* + - packages/cell-toolbar/* + - packages/cell-toolbar-extension/**/* + - packages/cell-toolbar-extension/* + pkg:cells: - packages/cells/**/* - packages/cells/* @@ -58,6 +66,12 @@ pkg:codeeditor: - packages/codeeditor/**/* - packages/codeeditor/* +pkg:collaboration: + - packages/collaboration/**/* + - packages/collaboration/* + - packages/collaboration-extension/**/* + - packages/collaboration-extension/* + pkg:codemirror: - packages/codemirror/**/* - packages/codemirror/* @@ -178,6 +192,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/* diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 799180a..3370596 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,7 +2,7 @@ Thanks for contributing to JupyterLab! Please fill out the following items to submit a pull request. See the contributing guidelines for more information: -https://github.com/jupyterlab/jupyterlab/blob/3.3.x/CONTRIBUTING.md +https://github.com/ElixirNote/elixirnote/blob/main/CONTRIBUTING.md --> ## References diff --git a/.github/workflows/answered.yml b/.github/workflows/answered.yml index 0d358f5..c15d2d9 100644 --- a/.github/workflows/answered.yml +++ b/.github/workflows/answered.yml @@ -14,13 +14,11 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v5 with: days-before-pr-stale: -1 days-before-pr-close: -1 - skip-stale-issue-message: true - days-before-issue-stale: 30 - days-before-issue-close: 7 + days-before-issue-stale: 7 + days-before-issue-close: 5 stale-issue-label: 'status:Closing as Answered' - stale-issue-message: '.' only-issue-labels: 'status:Answered' diff --git a/.github/workflows/auto_author_assign.yml b/.github/workflows/auto_author_assign.yml index c7a7902..86fce6f 100644 --- a/.github/workflows/auto_author_assign.yml +++ b/.github/workflows/auto_author_assign.yml @@ -12,4 +12,4 @@ jobs: assign-author: runs-on: ubuntu-latest steps: - - uses: toshimaru/auto-author-assign@v1.3.4 + - uses: toshimaru/auto-author-assign@v1.6.1 diff --git a/.github/workflows/benchmark-report.yml b/.github/workflows/benchmark-report.yml new file mode 100644 index 0000000..81f7a95 --- /dev/null +++ b/.github/workflows/benchmark-report.yml @@ -0,0 +1,82 @@ +# 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 + if: github.event.workflow_run.conclusion == 'success' + steps: + - name: 'Download artifact' + uses: actions/github-script@v6 + with: + script: | + var artifacts = await github.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.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.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.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: [report, memory-report].join('\n') + }) + } else { + await github.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 0000000..3e09464 --- /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-20.04 + + env: + BENCHMARK_NUMBER_SAMPLES: 100 + + steps: + - name: Checkout + uses: actions/checkout@v3 + 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 'master@{7 days ago}')" >> $GITHUB_ENV + echo "NEW_REF_SHA=$(git rev-parse 'master')" >> $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@v1 + + # 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-20.04 + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - 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.2 + 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 index c42f935..a2b77b8 100644 --- a/.github/workflows/check-i18n.yml +++ b/.github/workflows/check-i18n.yml @@ -8,36 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '14.x' - - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.9 - - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - name: Cache pip - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip-i18n-${{ hashFiles('setup.cfg') }} - restore-keys: | - ${{ runner.os }}-pip-i18n- - ${{ runner.os }}-pip- + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install dependencies run: | - python -m pip install -U pip - python -m pip install jupyterlab-translate~=1.0 + python -m pip install -U pip jupyterlab-translate~=1.0 - name: Compute hash id: currentHash diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml index 3f9b0a4..22b3171 100644 --- a/.github/workflows/check-release.yml +++ b/.github/workflows/check-release.yml @@ -2,9 +2,9 @@ name: Check Release on: push: - branches: [3.3.x] + branches: [master] pull_request: - branches: [3.3.x] + branches: [master] release: types: [published] @@ -13,65 +13,22 @@ jobs: check_release: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: group: [check_release, link_check] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '14.x' - - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.9 - - # Cache yarn - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - name: Cache pip - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip-${{ hashFiles('setup.cfg') }} - restore-keys: | - ${{ runner.os }}-pip- - ${{ runner.os }}-pip- - - - name: Cache checked links build - uses: actions/cache@v2 - if: ${{ matrix.group == 'link_check' }} - with: - path: ~/.cache/pytest-link-check - key: ${{ runner.os }}-linkcheck-${{ hashFiles('**/*.rst', '**/*.md') }}-changelog - restore-keys: | - ${{ runner.os }}-linkcheck- + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Check Release if: ${{ matrix.group == 'check_release' }} uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v1 - env: - RH_VERSION_SPEC: next with: token: ${{ secrets.GITHUB_TOKEN }} + version_spec: next - name: Run Link Check if: ${{ matrix.group == 'link_check' }} @@ -79,8 +36,8 @@ jobs: - name: Upload Assets if: ${{ matrix.group == 'check_release' }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: dist-files + 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 c678181..e214ace 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,10 +7,10 @@ name: "CodeQL" on: push: - branches: [3.3.x] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [3.3.x] + branches: [master] schedule: - cron: '0 8 * * 3' @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 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 0000000..725feab --- /dev/null +++ b/.github/workflows/enforce-label.yml @@ -0,0 +1,13 @@ +name: Enforce PR label + +on: + pull_request: + 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 0000000..b508c54 --- /dev/null +++ b/.github/workflows/galata-update.yml @@ -0,0 +1,115 @@ +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-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v3 + 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: hub 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 + + 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-20.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.9.9'] + + steps: + - name: Checkout JupyterLab + uses: actions/checkout@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + path: core + + - name: Checkout demo project + uses: actions/checkout@v3 + 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: Configure git to use https + run: git config --global hub.protocol https + + - name: Checkout the branch from the PR that triggered the job + working-directory: core + run: hub 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 diff --git a/.github/workflows/galata.yml b/.github/workflows/galata.yml index c5f6bf4..8574f22 100644 --- a/.github/workflows/galata.yml +++ b/.github/workflows/galata.yml @@ -5,54 +5,28 @@ on: branches: - master pull_request: - branches: - - '*' jobs: - build: + test: name: Visual Regression Tests - timeout-minutes: 40 + timeout-minutes: 80 runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 - - name: Install node - uses: actions/setup-node@v2 - with: - node-version: '14.x' - - name: Install Python - uses: actions/setup-python@v2 - with: - python-version: 3.8 + uses: actions/checkout@v3 - - name: Cache pip on Linux - uses: actions/cache@v1 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-3.8-${{ hashFiles('**/requirements.txt', 'setup.cfg') }} - restore-keys: | - ${{ runner.os }}-pip-3.8 - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v1 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + - 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 run: | cd galata - # Mount a volume to overwrite the server configuration jlpm start 2>&1 > /tmp/jupyterlab_server.log & - name: Install browser @@ -72,20 +46,24 @@ jobs: run: | cd galata jlpm run test + 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@v2 + uses: actions/upload-artifact@v3 with: - name: galata-test-assets + name: jupyterlab-galata-test-assets path: | + galata/test-jupyterlab-results galata/test-results - name: Upload Galata Test report if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: galata-report + name: jupyterlab-galata-report path: | galata/playwright-report @@ -93,3 +71,108 @@ jobs: if: always() run: | cat /tmp/jupyterlab_server.log + + test-documentation: + name: Visual Regression Documentation + # 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-20.04 + strategy: + matrix: + # Freeze Python version because it appears in console header + python-version: ['3.9.9'] + steps: + - name: Checkout JupyterLab + uses: actions/checkout@v3 + with: + path: core + + - name: Checkout demo project + uses: actions/checkout@v3 + 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: 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 }} + 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 0000000..bf8a81e --- /dev/null +++ b/.github/workflows/license-header.yml @@ -0,0 +1,52 @@ +name: Fix License Headers + +on: + pull_request: + +permissions: + contents: write + pull-requests: write + +jobs: + header-license-fix: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + 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: hub 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: Get modified files in the staging directory + id: changed-files + uses: tj-actions/changed-files@v29.0.2 + + - name: Apply Changes + if: steps.changed-files.outputs.any_changed == 'true' + shell: bash -l {0} + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git add * + git commit -m "Automatic application of license header" + + - name: Push fixes + if: steps.changed-files.outputs.any_changed == 'true' + shell: bash -l {0} + run: | + 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 97d13b6..0000000 --- a/.github/workflows/linuxjs-flaky-tests.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Linux JS Flaky Tests - -on: - push: - branches: [3.3.x] - pull_request: - branches: [3.3.x] - release: - types: [published] - -jobs: - linuxjs: - name: JS - strategy: - matrix: - group: [js-apputils, js-services] - fail-fast: false - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Cache pip on Linux - uses: actions/cache@v1 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ hashFiles('**/requirements.txt', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python }} - - # Cache yarn - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v1 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - 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 823e3c3..7362247 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.3.x] + branches: [master] pull_request: - branches: [3.3.x] + branches: [master] release: types: [published] @@ -13,47 +13,61 @@ jobs: name: JS strategy: matrix: - group: [js-application, js-cells, js-codeeditor, js-codemirror, js-completer, js-console, js-coreutils, js-csvviewer, js-debugger, js-docmanager, js-docregistry, js-documentsearch, js-filebrowser, js-fileeditor, js-imageviewer, js-inspector, js-logconsole, js-mainmenu, js-nbformat, js-notebook, js-observables, js-outputarea, js-rendermime, js-settingregistry, js-statedb, js-statusbar, js-terminal, js-toc, js-translation, js-ui-components, js-testutils] + group: + [ + js-application, + js-apputils, + js-cell-toolbar, + js-cells, + js-codeeditor, + js-codemirror, + js-collaboration, + js-completer, + js-console, + js-coreutils, + js-csvviewer, + js-debugger, + js-docmanager, + js-docregistry, + js-documentsearch, + js-filebrowser, + js-fileeditor, + js-imageviewer, + js-inspector, + js-logconsole, + js-lsp, + js-mainmenu, + js-nbformat, + js-notebook, + js-observables, + js-outputarea, + js-rendermime, + js-services, + js-settingregistry, + js-statedb, + js-statusbar, + js-terminal, + js-toc, + js-translation, + js-ui-components, + js-testutils, + ] fail-fast: false runs-on: ubuntu-20.04 timeout-minutes: 20 steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Cache pip on Linux - uses: actions/cache@v1 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ hashFiles('**/requirements.txt', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python }} + - name: Checkout + uses: actions/checkout@v3 - # Cache yarn - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v1 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + - 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 }} diff --git a/.github/workflows/linuxtests.yml b/.github/workflows/linuxtests.yml index c1826f9..c7e345d 100644 --- a/.github/workflows/linuxtests.yml +++ b/.github/workflows/linuxtests.yml @@ -2,9 +2,9 @@ name: Linux Tests on: push: - branches: [3.3.x] + branches: [master] pull_request: - branches: [3.3.x] + branches: [master] release: types: [published] @@ -14,74 +14,49 @@ jobs: strategy: matrix: group: [integrity, integrity2, integrity3, release_test, docs, usage, usage2, splice_source, python, examples, interop, nonode, linkcheck, lint] - python: [3.6, 3.8] + # This will be used by the base setup action + python-version: ["3.7", "3.10"] include: - group: release_test upload-output: true exclude: - group: integrity - python: 3.6 + python-version: "3.7" - group: integrity2 - python: 3.6 + python-version: "3.7" - group: integrity3 - python: 3.6 + python-version: "3.7" - group: release_test - python: 3.6 + python-version: "3.7" - group: docs - python: 3.6 + python-version: "3.7" - group: usage - python: 3.6 + python-version: "3.7" - group: usage2 - python: 3.6 + python-version: "3.7" - group: linkcheck - python: 3.6 + python-version: "3.7" - group: nonode - python: 3.6 + python-version: "3.7" - group: lint - python: 3.6 + python-version: "3.7" - group: examples - python: 3.6 + python-version: "3.7" - group: splice_source - python: 3.6 + python-version: "3.7" fail-fast: false - timeout-minutes: 30 + timeout-minutes: 45 runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python }} + - name: Checkout + uses: actions/checkout@v3 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Setup firefox uses: browser-actions/setup-firefox@latest - - name: Cache pip on Linux - uses: actions/cache@v2 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ hashFiles('**/requirements.txt', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python }} - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - name: Install dependencies env: GROUP: ${{ matrix.group }} @@ -97,7 +72,80 @@ 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 + + test_minimum_versions: + name: Test Minimum Versions + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + with: + python_version: "3.7" + - name: Install miniumum 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@v3 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: Install dependencies + run: | + bash ./scripts/ci_install.sh + - name: Build SDist + run: | + pip install build + python -m build --sdist + - uses: actions/upload-artifact@v3 + with: + name: "sdist" + path: dist/*.tar.gz + + test_sdist: + runs-on: ubuntu-latest + needs: [make_sdist] + name: Install from SDist and Test + timeout-minutes: 20 + steps: + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: Download sdist + uses: actions/download-artifact@v3 + - name: Install From SDist + run: | + set -ex + cd sdist + mkdir test + tar --strip-components=1 -zxvf *.tar.gz -C ./test + cd test + pip install -e .[dev,test] + pip install pytest-github-actions-annotate-failures + - name: Run Test + run: | + cd sdist/test + pytest -vv || pytest -vv --lf + + pre-commit: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v3 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: Install Jupyterlab + run: pip install -e . + - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 478e929..7565595 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -14,7 +14,7 @@ jobs: lock: runs-on: ubuntu-20.04 steps: - - uses: dessant/lock-threads@v2 + - uses: dessant/lock-threads@v3 with: github-token: ${{ github.token }} issue-lock-inactive-days: '180' diff --git a/.github/workflows/macostests.yml b/.github/workflows/macostests.yml index a71930b..16c3e71 100644 --- a/.github/workflows/macostests.yml +++ b/.github/workflows/macostests.yml @@ -2,9 +2,9 @@ name: macOS Tests on: push: - branches: [3.3.x] + branches: [master] pull_request: - branches: [3.3.x] + branches: [master] release: types: [published] @@ -14,55 +14,20 @@ jobs: strategy: matrix: group: [integrity, python, usage, usage2] - python: [3.8] + python-version: [3.8] fail-fast: false timeout-minutes: 45 runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python }} + - name: Checkout + uses: actions/checkout@v3 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Setup firefox uses: browser-actions/setup-firefox@latest - - name: Cache pip on Linux - uses: actions/cache@v2 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ hashFiles('**/requirements.txt', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python }} - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache checked links build - uses: actions/cache@v2 - if: ${{ matrix.group == 'linkcheck' }} - with: - path: ~/.cache/pytest-link-check - key: ${{ runner.os }}-linkcheck-${{ hashFiles('**/*.rst') }}-changelog - restore-keys: | - ${{ runner.os }}-linkcheck- - - name: Install dependencies env: GROUP: ${{ matrix.group }} diff --git a/.github/workflows/reject-staging-changes.yml b/.github/workflows/reject-staging-changes.yml new file mode 100644 index 0000000..5c5fdd0 --- /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@v3 + + - name: Get modified files in the staging directory + id: modified-files-in-staging + uses: tj-actions/changed-files@v29.0.2 + 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 1960adc..76a1b23 100644 --- a/.github/workflows/windowstests.yml +++ b/.github/workflows/windowstests.yml @@ -2,9 +2,9 @@ name: Windows Tests on: push: - branches: [3.3.x] + branches: [master] pull_request: - branches: [3.3.x] + branches: [master] release: types: [published] @@ -18,40 +18,11 @@ jobs: runs-on: windows-latest timeout-minutes: 40 steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.6 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Cache pip on Windows - uses: actions/cache@v2 - if: startsWith(runner.os, 'Windows') - with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', 'setup.py') }}-2 - restore-keys: | - ${{ runner.os }}-pip- + - name: Checkout + uses: actions/checkout@v3 - # Cache yarn - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: Cache yarn - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}-2 - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Enable long paths - run: Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -Value 1 - shell: pwsh + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install dependencies env: diff --git a/.gitignore b/.gitignore index 5a9493b..08fcb4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # project files coverage/ +.eslintcache +.stylelintcache dev_mode/listings dev_mode/schemas @@ -9,6 +11,7 @@ dev_mode/workspaces dev_mode/stats.json docs/_build +docs/source/user/commands_list.md docs/api **/docs/source/_build @@ -28,9 +31,12 @@ jupyterlab/style.js jupyterlab/tests/**/static jupyterlab/tests/**/labextension +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 @@ -43,6 +49,7 @@ tests/**/.cache-loader galata/benchmark-results galata/playwright-report galata/test-results +galata/*benchmark-expected.json package_json.tar.gz @@ -53,7 +60,6 @@ node_modules *.tsbuildinfo lerna-debug.log yarn-error.log -storybook-static # python .cache @@ -117,7 +123,12 @@ junit.xml # ms IDE stuff *.code-workspace .history -.vscode -.vs +.vscode/* +!.vscode/extension.json .jupyter_releaser_checkout + +# generated LSP interfaces +packages/lsp/src/_* + +.jupyter_ystore.db diff --git a/.gitpod.yml b/.gitpod.yml index 4970d86..422ac3b 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -17,17 +17,28 @@ github: # 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 + - name: dev-mode + init: | + pip3 install -e ".[docs,test]" + jlpm install + jlpm run build + gp sync-done setup # 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 *"}}' + command: | + jupyter lab --dev-mode --watch --LabApp.token='' --LabApp.allow_origin=* --LabApp.tornado_settings='{"headers": {"Content-Security-Policy": "frame-ancestors *"}}' + - name: documentation + init: | + gp sync-await setup + cd docs + make html + command: | + 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 new file mode 100644 index 0000000..f0b93fe --- /dev/null +++ b/.licenserc.yaml @@ -0,0 +1,41 @@ +header: + license: + spdx-id: BSD-3-Clause + copyright-owner: Jupyter Development Team + software-name: JupyterLab + content: | + Copyright (c) Jupyter Development Team. + Distributed under the terms of the Modified BSD License. + + paths-ignore: + - '**/*.ipynb' + - '**/*.json' + - '**/*.md' + - '**/*.svg' + - '**/*.yml' + - '**/*.yaml' + - '**/build' + - '**/lib' + - '**/node_modules' + - '**/MANIFEST.in' + - '**/static' + - '**/typings' + - '**/schemas' + - '**/themes' + - '*.map.js' + - '*.bundle.js' + - '**/.*' + - 'binder/postBuild' + - 'binder/start' + - 'coverage' + - 'dev_mode/style.js' + - 'examples/federated/example.cert' + - 'galata/test/jupyterlab/notebooks/' + - 'jupyterlab/staging' + - 'packages/codemirror/test/foo.grammar' + - 'packages/extensionmanager-extension/examples/listings/settings/@jupyterlab/extensionmanager-extension/plugin.jupyterlab-settings' + - 'typedoc-theme' + - 'LICENSE' + - 'yarn.lock' + + comment: on-failure diff --git a/.meeseeksdev.yml b/.meeseeksdev.yml index 165a153..96e0541 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 new file mode 100644 index 0000000..cc0d6ef --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,80 @@ +ci: + # skip any check that needs internet access + skip: [check-jsonschema, prettier, eslint, stylelint, integrity] + +default_language_version: + node: system + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.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 + + - repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + args: ['--line-length', '100'] + + - repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: + - id: isort + files: \.py$ + args: [--profile=black] + + - repo: https://github.com/pycqa/flake8 + rev: 5.0.4 + hooks: + - id: flake8 + additional_dependencies: + [ + 'flake8-bugbear==22.6.22', + 'flake8-implicit-str-concat==0.2.0' + ] + + - repo: https://github.com/sirosen/check-jsonschema + rev: 0.18.1 + hooks: + - id: check-jsonschema + name: 'Check GitHub Workflows' + files: ^\.github/workflows/ + types: [yaml] + args: ['--schemafile', 'https://json.schemastore.org/github-workflow'] + + - repo: local + hooks: + - id: prettier + name: prettier + entry: 'npm run prettier:files' + language: node + types_or: [json, markdown, ts, tsx, javascript, jsx, css] + - id: eslint + name: eslint + 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' + language: node + stages: [push] diff --git a/.prettierignore b/.prettierignore index e99efcb..99002c6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,7 @@ **/build **/node_modules **/lib +**/dist **/package.json **/static **/.ipynb_checkpoints @@ -18,17 +19,18 @@ 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/schemas jupyterlab/themes jupyterlab/geckodriver jupyterlab/staging/yarn.js 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 +typedoc-theme # jetbrains IDE stuff .idea/ @@ -39,3 +41,10 @@ examples/federated/labextensions # autogenerated from a lot of css in jlab packages/nbconvert-css/style/index.css + +# autogenerated files for documentation +docs/source/user/commands_list.md +galata/test/documentation/commands.test.ts-snapshots/commandsList-documentation-linux.json + +# generated LSP interfaces +packages/lsp/src/_ diff --git a/.prettierrc b/.prettierrc index 1950328..b0a179d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,4 +2,4 @@ "singleQuote": true, "trailingComma": "none", "arrowParens": "avoid" -} \ No newline at end of file +} diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..b5341c4 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1 @@ +packages/nbconvert-css/style/index.css diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml new file mode 100644 index 0000000..2a215b5 --- /dev/null +++ b/.stylelintrc.yaml @@ -0,0 +1,32 @@ +$schema: https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/stylelintrc.json + +extends: + - stylelint-config-recommended + - stylelint-config-standard + - stylelint-prettier/recommended + +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 diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29..69b4989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,6400 @@ +--- +github_url: 'https://github.com/jupyterlab/jupyterlab/blob/master/CHANGELOG.md' +--- + + + +(changelog)= + +# JupyterLab Changelog + +## 4.0 + + + +## 4.0.0a27 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a26...67900403c47675509a7f43f34ff37b57e9cb99c5)) + +### New features added + +- Integrate `jupyterlab-lsp` into `jupyterlab` [#12534](https://github.com/jupyterlab/jupyterlab/pull/12534) ([@trungleduc](https://github.com/trungleduc)) + +### Enhancements made + +- Set `Contents.ContentType` to string [#12875](https://github.com/jupyterlab/jupyterlab/pull/12875) ([@trungleduc](https://github.com/trungleduc)) +- Add trustbydefault param to htmlviewer-extension [#12868](https://github.com/jupyterlab/jupyterlab/pull/12868) ([@oscar6echo](https://github.com/oscar6echo)) +- Moved theme Map and added API to use it from other dependencies [#12861](https://github.com/jupyterlab/jupyterlab/pull/12861) ([@JohanMabille](https://github.com/JohanMabille)) +- Removes info about meeting notes on Binder [#12847](https://github.com/jupyterlab/jupyterlab/pull/12847) ([@jweill-aws](https://github.com/jweill-aws)) +- 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)) +- Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@jweill-aws](https://github.com/jweill-aws)) +- Debugger: Make kernel source list react based [#12751](https://github.com/jupyterlab/jupyterlab/pull/12751) ([@vidartf](https://github.com/vidartf)) +- Optimize debugger editor `eachLine` loops [#12746](https://github.com/jupyterlab/jupyterlab/pull/12746) ([@vidartf](https://github.com/vidartf)) +- Add resize handle for scrolled cell outputs [#12740](https://github.com/jupyterlab/jupyterlab/pull/12740) ([@peytondmurray](https://github.com/peytondmurray)) +- Bump xtermjs to latest [#12715](https://github.com/jupyterlab/jupyterlab/pull/12715) ([@yuvipanda](https://github.com/yuvipanda)) +- Edit Gitpod configuration to be able to work on the documentation [#12697](https://github.com/jupyterlab/jupyterlab/pull/12697) ([@jtpio](https://github.com/jtpio)) +- remove reference to blueprint.js in css [#12663](https://github.com/jupyterlab/jupyterlab/pull/12663) ([@fcollonval](https://github.com/fcollonval)) +- Integrate `jupyterlab-lsp` into `jupyterlab` [#12534](https://github.com/jupyterlab/jupyterlab/pull/12534) ([@trungleduc](https://github.com/trungleduc)) +- RTC left panel [#12095](https://github.com/jupyterlab/jupyterlab/pull/12095) ([@martinRenou](https://github.com/martinRenou)) +- Migrate to Codemirror 6 [#11638](https://github.com/jupyterlab/jupyterlab/pull/11638) ([@JohanMabille](https://github.com/JohanMabille)) + +### Bugs fixed + +- 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)) +- 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)) + +### Maintenance and upkeep improvements + +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12893](https://github.com/jupyterlab/jupyterlab/pull/12893) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12813](https://github.com/jupyterlab/jupyterlab/pull/12813) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12796](https://github.com/jupyterlab/jupyterlab/pull/12796) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12771](https://github.com/jupyterlab/jupyterlab/pull/12771) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12741](https://github.com/jupyterlab/jupyterlab/pull/12741) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12694](https://github.com/jupyterlab/jupyterlab/pull/12694) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- Switch to hatch backend [#12606](https://github.com/jupyterlab/jupyterlab/pull/12606) ([@blink1073](https://github.com/blink1073)) + +### Documentation improvements + +- 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)) +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@jweill-aws](https://github.com/jweill-aws)) +- 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)) +- Switch to hatch backend [#12606](https://github.com/jupyterlab/jupyterlab/pull/12606) ([@blink1073](https://github.com/blink1073)) +- RTC left panel [#12095](https://github.com/jupyterlab/jupyterlab/pull/12095) ([@martinRenou](https://github.com/martinRenou)) + +### API and Breaking Changes + +- Fixes renaming files from title while using a custom drive [#12849](https://github.com/jupyterlab/jupyterlab/pull/12849) ([@hbcarlos](https://github.com/hbcarlos)) +- RTC left panel [#12095](https://github.com/jupyterlab/jupyterlab/pull/12095) ([@martinRenou](https://github.com/martinRenou)) +- Migrate to Codemirror 6 [#11638](https://github.com/jupyterlab/jupyterlab/pull/11638) ([@JohanMabille](https://github.com/JohanMabille)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-06-09&to=2022-08-08&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-06-09..2022-08-08&type=Issues) | [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2022-06-09..2022-08-08&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-06-09..2022-08-08&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-06-09..2022-08-08&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-06-09..2022-08-08&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-06-09..2022-08-08&type=Issues) | [@dlqqq](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adlqqq+updated%3A2022-06-09..2022-08-08&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-06-09..2022-08-08&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-06-09..2022-08-08&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-06-09..2022-08-08&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-06-09..2022-08-08&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-06-09..2022-08-08&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2022-06-09..2022-08-08&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-06-09..2022-08-08&type=Issues) | [@hsuanxyz](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahsuanxyz+updated%3A2022-06-09..2022-08-08&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2022-06-09..2022-08-08&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-06-09..2022-08-08&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2022-06-09..2022-08-08&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-06-09..2022-08-08&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-06-09..2022-08-08&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-06-09..2022-08-08&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-06-09..2022-08-08&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-06-09..2022-08-08&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-06-09..2022-08-08&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-06-09..2022-08-08&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-06-09..2022-08-08&type=Issues) | [@oscar6echo](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aoscar6echo+updated%3A2022-06-09..2022-08-08&type=Issues) | [@peytondmurray](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apeytondmurray+updated%3A2022-06-09..2022-08-08&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apre-commit-ci+updated%3A2022-06-09..2022-08-08&type=Issues) | [@RobbyPratl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ARobbyPratl+updated%3A2022-06-09..2022-08-08&type=Issues) | [@siddartha-10](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asiddartha-10+updated%3A2022-06-09..2022-08-08&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-06-09..2022-08-08&type=Issues) | [@thetorpedodog](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athetorpedodog+updated%3A2022-06-09..2022-08-08&type=Issues) | [@thomasaarholt](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athomasaarholt+updated%3A2022-06-09..2022-08-08&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-06-09..2022-08-08&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2022-06-09..2022-08-08&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-06-09..2022-08-08&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2022-06-09..2022-08-08&type=Issues) | [@yangql176](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayangql176+updated%3A2022-06-09..2022-08-08&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2022-06-09..2022-08-08&type=Issues) + + + +## 4.0.0a26 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a25...09d12a0bbfdcecbfeb410a434c7111af88547c69)) + +### New features added + +- Persistent side-by-side ratio setting [#12633](https://github.com/jupyterlab/jupyterlab/pull/12633) ([@echarles](https://github.com/echarles)) + +### Enhancements made + +- Make password inputs not give away how many characters were typed [#12659](https://github.com/jupyterlab/jupyterlab/pull/12659) ([@jasongrout](https://github.com/jasongrout)) +- Persistent side-by-side ratio setting [#12633](https://github.com/jupyterlab/jupyterlab/pull/12633) ([@echarles](https://github.com/echarles)) +- add "close all tabs" context action [#12620](https://github.com/jupyterlab/jupyterlab/pull/12620) ([@rursprung](https://github.com/rursprung)) +- Fix the side-by-side cell resize handle [#12609](https://github.com/jupyterlab/jupyterlab/pull/12609) ([@echarles](https://github.com/echarles)) +- Invert relationship between launcher and filebrowser [#12585](https://github.com/jupyterlab/jupyterlab/pull/12585) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Remove ipywidgets message count in the execution indicator model [#12665](https://github.com/jupyterlab/jupyterlab/pull/12665) ([@trungleduc](https://github.com/trungleduc)) +- 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)) +- Pin exactly jupyter_ydoc [#12602](https://github.com/jupyterlab/jupyterlab/pull/12602) ([@davidbrochart](https://github.com/davidbrochart)) +- Always check local packages against abspath [#10662](https://github.com/jupyterlab/jupyterlab/pull/10662) ([@mlucool](https://github.com/mlucool)) + +### Maintenance and upkeep improvements + +- [pre-commit.ci] pre-commit autoupdate [#12658](https://github.com/jupyterlab/jupyterlab/pull/12658) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- 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)) +- [pre-commit.ci] pre-commit autoupdate [#12626](https://github.com/jupyterlab/jupyterlab/pull/12626) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- Remove unneeded build:all and test config [#12618](https://github.com/jupyterlab/jupyterlab/pull/12618) ([@fcollonval](https://github.com/fcollonval)) +- Fix `documentsearch-extension` plugin id [#12604](https://github.com/jupyterlab/jupyterlab/pull/12604) ([@jtpio](https://github.com/jtpio)) +- Fix GitHub user rename for check-link [#12601](https://github.com/jupyterlab/jupyterlab/pull/12601) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- 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)) +- Fix `documentsearch-extension` plugin id [#12604](https://github.com/jupyterlab/jupyterlab/pull/12604) ([@jtpio](https://github.com/jtpio)) +- Fix GitHub user rename for check-link [#12601](https://github.com/jupyterlab/jupyterlab/pull/12601) ([@fcollonval](https://github.com/fcollonval)) +- Invert relationship between launcher and filebrowser [#12585](https://github.com/jupyterlab/jupyterlab/pull/12585) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-05-19&to=2022-06-09&type=c)) + +[@a3626a](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aa3626a+updated%3A2022-05-19..2022-06-09&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-05-19..2022-06-09&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-05-19..2022-06-09&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-05-19..2022-06-09&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-05-19..2022-06-09&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-05-19..2022-06-09&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-05-19..2022-06-09&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-05-19..2022-06-09&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-05-19..2022-06-09&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-05-19..2022-06-09&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-05-19..2022-06-09&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-05-19..2022-06-09&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-05-19..2022-06-09&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-05-19..2022-06-09&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apre-commit-ci+updated%3A2022-05-19..2022-06-09&type=Issues) | [@rursprung](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arursprung+updated%3A2022-05-19..2022-06-09&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-05-19..2022-06-09&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-05-19..2022-06-09&type=Issues) + +## 4.0.0a25 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a24...9cfad42aac66025f5ce2f9a33f91bfc83cff5b49)) + +### Enhancements made + +- Fix collaborative document cleanup [#12595](https://github.com/jupyterlab/jupyterlab/pull/12595) ([@davidbrochart](https://github.com/davidbrochart)) +- Use customizable toolbar for topbar [#12586](https://github.com/jupyterlab/jupyterlab/pull/12586) ([@fcollonval](https://github.com/fcollonval)) +- Stop creating search provider for status [#12564](https://github.com/jupyterlab/jupyterlab/pull/12564) ([@fcollonval](https://github.com/fcollonval)) +- Add "Open in Simple Mode" contextMenu option [#12532](https://github.com/jupyterlab/jupyterlab/pull/12532) ([@divyansshhh](https://github.com/divyansshhh)) +- Check-all checkbox should be unchecked when current directory is empty [#12510](https://github.com/jupyterlab/jupyterlab/pull/12510) ([@gabalafou](https://github.com/gabalafou)) +- Add line history (via arrow up/down) to all `Stdin` widgets in cell outputs [#12502](https://github.com/jupyterlab/jupyterlab/pull/12502) ([@telamonian](https://github.com/telamonian)) +- Allow downstream extension to set toolbar layout [#12499](https://github.com/jupyterlab/jupyterlab/pull/12499) ([@fcollonval](https://github.com/fcollonval)) +- Display default value in setting editor for changed values [#12468](https://github.com/jupyterlab/jupyterlab/pull/12468) ([@echarles](https://github.com/echarles)) +- Setting to use the advanced setting editor for the settings [#12466](https://github.com/jupyterlab/jupyterlab/pull/12466) ([@echarles](https://github.com/echarles)) +- Add ability to open settings editor to specific plugin's settings [#12398](https://github.com/jupyterlab/jupyterlab/pull/12398) ([@marthacryan](https://github.com/marthacryan)) +- Table of content refactor [#12374](https://github.com/jupyterlab/jupyterlab/pull/12374) ([@fcollonval](https://github.com/fcollonval)) +- Add CodeViewer widget and openCodeViewer command [#12365](https://github.com/jupyterlab/jupyterlab/pull/12365) ([@ajbozarth](https://github.com/ajbozarth)) +- Load/auto-save document from the back-end using y-py [#12360](https://github.com/jupyterlab/jupyterlab/pull/12360) ([@davidbrochart](https://github.com/davidbrochart)) +- Notebook search based on data model [#11689](https://github.com/jupyterlab/jupyterlab/pull/11689) ([@fcollonval](https://github.com/fcollonval)) +- Customize layout from settings [#11614](https://github.com/jupyterlab/jupyterlab/pull/11614) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Building extensions fail if not using latest patch [#12571](https://github.com/jupyterlab/jupyterlab/pull/12571) ([@ajbozarth](https://github.com/ajbozarth)) +- Fix loading toolbar factory twice [#12556](https://github.com/jupyterlab/jupyterlab/pull/12556) ([@fcollonval](https://github.com/fcollonval)) +- fixed shouldOverwrite is never called when rename target exists [#12543](https://github.com/jupyterlab/jupyterlab/pull/12543) ([@ephes](https://github.com/ephes)) +- Fix file browser search highlighting bug [#12538](https://github.com/jupyterlab/jupyterlab/pull/12538) ([@marthacryan](https://github.com/marthacryan)) +- Allow users to yarn link @jupyterlab/builder [#12533](https://github.com/jupyterlab/jupyterlab/pull/12533) ([@ajbozarth](https://github.com/ajbozarth)) +- Handle missing `preferredPath` from the page config [#12521](https://github.com/jupyterlab/jupyterlab/pull/12521) ([@jtpio](https://github.com/jtpio)) +- 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)) +- Get Auto Close Brackets working consistently in Consoles [#12508](https://github.com/jupyterlab/jupyterlab/pull/12508) ([@Jessie-Newman](https://github.com/Jessie-Newman)) +- Ensure settings editor is attached before activation [#12507](https://github.com/jupyterlab/jupyterlab/pull/12507) ([@fcollonval](https://github.com/fcollonval)) +- Fixes behavior of `maxNumberOutputs` [#12498](https://github.com/jupyterlab/jupyterlab/pull/12498) ([@telamonian](https://github.com/telamonian)) +- Handled new dialog creation with no buttons [#12496](https://github.com/jupyterlab/jupyterlab/pull/12496) ([@Jnnamchi](https://github.com/Jnnamchi)) +- Setting form editor has a formState to avoid focus lost [#12470](https://github.com/jupyterlab/jupyterlab/pull/12470) ([@echarles](https://github.com/echarles)) +- Move cell toolbar below search document widget [#12467](https://github.com/jupyterlab/jupyterlab/pull/12467) ([@fcollonval](https://github.com/fcollonval)) +- Signal should only export ISignal publicly [#12464](https://github.com/jupyterlab/jupyterlab/pull/12464) ([@fcollonval](https://github.com/fcollonval)) +- Focus not set when clicking on cell margin [#12447](https://github.com/jupyterlab/jupyterlab/pull/12447) ([@fcollonval](https://github.com/fcollonval)) + +### Maintenance and upkeep improvements + +- Add bump linters commit to blame ignore [#12594](https://github.com/jupyterlab/jupyterlab/pull/12594) ([@fcollonval](https://github.com/fcollonval)) +- Remove deprecated SplitPanel [#12593](https://github.com/jupyterlab/jupyterlab/pull/12593) ([@afshin](https://github.com/afshin)) +- Use error names instead of messages for validation [#12591](https://github.com/jupyterlab/jupyterlab/pull/12591) ([@afshin](https://github.com/afshin)) +- [pre-commit.ci] pre-commit autoupdate [#12587](https://github.com/jupyterlab/jupyterlab/pull/12587) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- Bump linters [#12582](https://github.com/jupyterlab/jupyterlab/pull/12582) ([@fcollonval](https://github.com/fcollonval)) +- Unbump the major version of rendermime-interfaces [#12581](https://github.com/jupyterlab/jupyterlab/pull/12581) ([@fcollonval](https://github.com/fcollonval)) +- Force crypto resolution [#12576](https://github.com/jupyterlab/jupyterlab/pull/12576) ([@fcollonval](https://github.com/fcollonval)) +- Fix documentation UI test for extension manager search [#12552](https://github.com/jupyterlab/jupyterlab/pull/12552) ([@fcollonval](https://github.com/fcollonval)) +- Add cell-toolbar to CI and labeler [#12551](https://github.com/jupyterlab/jupyterlab/pull/12551) ([@fcollonval](https://github.com/fcollonval)) +- Fixes user package [#12548](https://github.com/jupyterlab/jupyterlab/pull/12548) ([@hbcarlos](https://github.com/hbcarlos)) +- Re-align `cell-toolbar` version [#12528](https://github.com/jupyterlab/jupyterlab/pull/12528) ([@jtpio](https://github.com/jtpio)) +- Update documentation snapshot [#12515](https://github.com/jupyterlab/jupyterlab/pull/12515) ([@fcollonval](https://github.com/fcollonval)) +- Rename `registerFactory` to `addFactory` in `IToolbarWidgetRegistry` [#12513](https://github.com/jupyterlab/jupyterlab/pull/12513) ([@fcollonval](https://github.com/fcollonval)) +- Deduplicates some packages in yarn.lock [#12512](https://github.com/jupyterlab/jupyterlab/pull/12512) ([@fcollonval](https://github.com/fcollonval)) +- Revert "Merge branch 'commenting-extension' into master" [#12511](https://github.com/jupyterlab/jupyterlab/pull/12511) ([@jtpio](https://github.com/jtpio)) +- Allow bot PRs to be automatically labeled [#12509](https://github.com/jupyterlab/jupyterlab/pull/12509) ([@blink1073](https://github.com/blink1073)) +- Inverse dependencies link between translation and rendermime interfaces [#12493](https://github.com/jupyterlab/jupyterlab/pull/12493) ([@fcollonval](https://github.com/fcollonval)) +- Require y-py>=0.4.6 [#12486](https://github.com/jupyterlab/jupyterlab/pull/12486) ([@davidbrochart](https://github.com/davidbrochart)) +- 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)) +- Check data based config [#12116](https://github.com/jupyterlab/jupyterlab/pull/12116) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Use customizable toolbar for topbar [#12586](https://github.com/jupyterlab/jupyterlab/pull/12586) ([@fcollonval](https://github.com/fcollonval)) +- Bump linters [#12582](https://github.com/jupyterlab/jupyterlab/pull/12582) ([@fcollonval](https://github.com/fcollonval)) +- Add "Open in Simple Mode" contextMenu option [#12532](https://github.com/jupyterlab/jupyterlab/pull/12532) ([@divyansshhh](https://github.com/divyansshhh)) +- Rename `registerFactory` to `addFactory` in `IToolbarWidgetRegistry` [#12513](https://github.com/jupyterlab/jupyterlab/pull/12513) ([@fcollonval](https://github.com/fcollonval)) +- Revert "Merge branch 'commenting-extension' into master" [#12511](https://github.com/jupyterlab/jupyterlab/pull/12511) ([@jtpio](https://github.com/jtpio)) +- Inverse dependencies link between translation and rendermime interfaces [#12493](https://github.com/jupyterlab/jupyterlab/pull/12493) ([@fcollonval](https://github.com/fcollonval)) +- Table of content refactor [#12374](https://github.com/jupyterlab/jupyterlab/pull/12374) ([@fcollonval](https://github.com/fcollonval)) +- Load/auto-save document from the back-end using y-py [#12360](https://github.com/jupyterlab/jupyterlab/pull/12360) ([@davidbrochart](https://github.com/davidbrochart)) +- Check data based config [#12116](https://github.com/jupyterlab/jupyterlab/pull/12116) ([@fcollonval](https://github.com/fcollonval)) +- Customize layout from settings [#11614](https://github.com/jupyterlab/jupyterlab/pull/11614) ([@fcollonval](https://github.com/fcollonval)) + +### API and Breaking Changes + +- Fix file browser search highlighting bug [#12538](https://github.com/jupyterlab/jupyterlab/pull/12538) ([@marthacryan](https://github.com/marthacryan)) +- Rename `registerFactory` to `addFactory` in `IToolbarWidgetRegistry` [#12513](https://github.com/jupyterlab/jupyterlab/pull/12513) ([@fcollonval](https://github.com/fcollonval)) +- Inverse dependencies link between translation and rendermime interfaces [#12493](https://github.com/jupyterlab/jupyterlab/pull/12493) ([@fcollonval](https://github.com/fcollonval)) +- Table of content refactor [#12374](https://github.com/jupyterlab/jupyterlab/pull/12374) ([@fcollonval](https://github.com/fcollonval)) +- Load/auto-save document from the back-end using y-py [#12360](https://github.com/jupyterlab/jupyterlab/pull/12360) ([@davidbrochart](https://github.com/davidbrochart)) + +### Deprecated features + +- Rename `registerFactory` to `addFactory` in `IToolbarWidgetRegistry` [#12513](https://github.com/jupyterlab/jupyterlab/pull/12513) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-04-25&to=2022-05-19&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-04-25..2022-05-19&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-04-25..2022-05-19&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-04-25..2022-05-19&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-04-25..2022-05-19&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-04-25..2022-05-19&type=Issues) | [@divyansshhh](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adivyansshhh+updated%3A2022-04-25..2022-05-19&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-04-25..2022-05-19&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-04-25..2022-05-19&type=Issues) | [@ephes](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aephes+updated%3A2022-04-25..2022-05-19&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-04-25..2022-05-19&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-04-25..2022-05-19&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-04-25..2022-05-19&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-04-25..2022-05-19&type=Issues) | [@Jessie-Newman](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJessie-Newman+updated%3A2022-04-25..2022-05-19&type=Issues) | [@Jnnamchi](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJnnamchi+updated%3A2022-04-25..2022-05-19&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-04-25..2022-05-19&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-04-25..2022-05-19&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-04-25..2022-05-19&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2022-04-25..2022-05-19&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-04-25..2022-05-19&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apre-commit-ci+updated%3A2022-04-25..2022-05-19&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2022-04-25..2022-05-19&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-04-25..2022-05-19&type=Issues) + +## 4.0.0a24 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a23...521ddc05627441a88e6ef4a498433ae90d0ff392)) + +### Enhancements made + +- Uses dark theme for Vega when JupyterLab theme is dark [#12411](https://github.com/jupyterlab/jupyterlab/pull/12411) ([@jweill-aws](https://github.com/jweill-aws)) +- 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)) +- File Browser: add support for filtering directories on search [#12342](https://github.com/jupyterlab/jupyterlab/pull/12342) ([@jtpio](https://github.com/jtpio)) +- Allow for an optional label for the uploader widget [#12333](https://github.com/jupyterlab/jupyterlab/pull/12333) ([@jtpio](https://github.com/jtpio)) +- Add argument `searchText` and `replaceText` to search and replace commands [#12310](https://github.com/jupyterlab/jupyterlab/pull/12310) ([@fcollonval](https://github.com/fcollonval)) +- Add checkboxes to file browser [#12299](https://github.com/jupyterlab/jupyterlab/pull/12299) ([@gabalafou](https://github.com/gabalafou)) +- Add a preferred-dir icon to the file browser crumbs [#12297](https://github.com/jupyterlab/jupyterlab/pull/12297) ([@echarles](https://github.com/echarles)) +- Use `importlib` instead of `pkg_resources` [#12293](https://github.com/jupyterlab/jupyterlab/pull/12293) ([@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)) +- Open terminal in cwd from launcher [#12250](https://github.com/jupyterlab/jupyterlab/pull/12250) ([@rccern](https://github.com/rccern)) +- Update completer part 3 [#12219](https://github.com/jupyterlab/jupyterlab/pull/12219) ([@trungleduc](https://github.com/trungleduc)) +- Add argument line and column to codemirror go to line command [#12204](https://github.com/jupyterlab/jupyterlab/pull/12204) ([@fcollonval](https://github.com/fcollonval)) +- Add support for filtering by field names in setting editor [#12082](https://github.com/jupyterlab/jupyterlab/pull/12082) ([@marthacryan](https://github.com/marthacryan)) +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@jweill-aws](https://github.com/jweill-aws)) +- position collapse heading button next to corresponding h tag (jupyterâ€Ļ [#11925](https://github.com/jupyterlab/jupyterlab/pull/11925) ([@Pugio](https://github.com/Pugio)) + +### Bugs fixed + +- Check if process is declared before optional chaining in makeSettings [#12454](https://github.com/jupyterlab/jupyterlab/pull/12454) ([@xiaochen-db](https://github.com/xiaochen-db)) +- Fix debugger extension error when notebooks is closed quickly [#12393](https://github.com/jupyterlab/jupyterlab/pull/12393) ([@afshin](https://github.com/afshin)) +- Changes Vega class name to match source code [#12378](https://github.com/jupyterlab/jupyterlab/pull/12378) ([@jweill-aws](https://github.com/jweill-aws)) +- Add parent header to input reply kernel message [#12376](https://github.com/jupyterlab/jupyterlab/pull/12376) ([@davidbrochart](https://github.com/davidbrochart)) +- Wait until file browser commands are ready before activating file browser widget [#12369](https://github.com/jupyterlab/jupyterlab/pull/12369) ([@afshin](https://github.com/afshin)) +- Toolbar items may not act on the proper target [#12368](https://github.com/jupyterlab/jupyterlab/pull/12368) ([@fcollonval](https://github.com/fcollonval)) +- Fix docmanager plugin name [#12356](https://github.com/jupyterlab/jupyterlab/pull/12356) ([@fcollonval](https://github.com/fcollonval)) +- Fix Yjs message [#12352](https://github.com/jupyterlab/jupyterlab/pull/12352) ([@davidbrochart](https://github.com/davidbrochart)) +- showDocsPanel should receive a boolean [#12346](https://github.com/jupyterlab/jupyterlab/pull/12346) ([@echarles](https://github.com/echarles)) +- Remove circular setting of source [#12338](https://github.com/jupyterlab/jupyterlab/pull/12338) ([@hbcarlos](https://github.com/hbcarlos)) +- Update reference snapshots for the extension manager [#12337](https://github.com/jupyterlab/jupyterlab/pull/12337) ([@jtpio](https://github.com/jtpio)) +- Remove cell id before saving the notebook [#12329](https://github.com/jupyterlab/jupyterlab/pull/12329) ([@hbcarlos](https://github.com/hbcarlos)) +- fix: Markdown cell generates duplicate toc content (#12312) [#12314](https://github.com/jupyterlab/jupyterlab/pull/12314) ([@yangql176](https://github.com/yangql176)) +- fix run cells breaking on non-header markdown cells [#12027](https://github.com/jupyterlab/jupyterlab/pull/12027) ([@andrewfulton9](https://github.com/andrewfulton9)) + +### Maintenance and upkeep improvements + +- Ignore the commit introducing import sort during blame [#12458](https://github.com/jupyterlab/jupyterlab/pull/12458) ([@krassowski](https://github.com/krassowski)) +- Use more explicit name for the releaser dist files uploaded as artifacts [#12448](https://github.com/jupyterlab/jupyterlab/pull/12448) ([@jtpio](https://github.com/jtpio)) +- Bump async from 2.6.3 to 2.6.4 [#12440](https://github.com/jupyterlab/jupyterlab/pull/12440) ([@dependabot](https://github.com/dependabot)) +- Removes FileEditorCodeWrapper [#12439](https://github.com/jupyterlab/jupyterlab/pull/12439) ([@hbcarlos](https://github.com/hbcarlos)) +- [pre-commit.ci] pre-commit autoupdate [#12438](https://github.com/jupyterlab/jupyterlab/pull/12438) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- Update to webpack 5.72 [#12423](https://github.com/jupyterlab/jupyterlab/pull/12423) ([@jtpio](https://github.com/jtpio)) +- Update benchmark snapshots as part of galata snapshots [#12413](https://github.com/jupyterlab/jupyterlab/pull/12413) ([@fcollonval](https://github.com/fcollonval)) +- Fix UI documentation CI [#12399](https://github.com/jupyterlab/jupyterlab/pull/12399) ([@fcollonval](https://github.com/fcollonval)) +- [pre-commit.ci] pre-commit autoupdate [#12391](https://github.com/jupyterlab/jupyterlab/pull/12391) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- Bump moment from 2.29.1 to 2.29.2 [#12384](https://github.com/jupyterlab/jupyterlab/pull/12384) ([@dependabot](https://github.com/dependabot)) +- type-only and lazy imports of settings widgets [#12364](https://github.com/jupyterlab/jupyterlab/pull/12364) ([@bollwyvl](https://github.com/bollwyvl)) +- Fix prettier [#12362](https://github.com/jupyterlab/jupyterlab/pull/12362) ([@jtpio](https://github.com/jtpio)) +- Use `execFileSync` instead of `execSync` when setting npm registry. [#12357](https://github.com/jupyterlab/jupyterlab/pull/12357) ([@max-schaefer](https://github.com/max-schaefer)) +- Update `webpack` dependencies [#12353](https://github.com/jupyterlab/jupyterlab/pull/12353) ([@jtpio](https://github.com/jtpio)) +- Add CI check that fails when files in the staging directory are modified [#12351](https://github.com/jupyterlab/jupyterlab/pull/12351) ([@galathinius](https://github.com/galathinius)) +- webpack: switch to the asset modules [#12350](https://github.com/jupyterlab/jupyterlab/pull/12350) ([@jtpio](https://github.com/jtpio)) +- Provide `IDocumentManager` in a separate plugin [#12349](https://github.com/jupyterlab/jupyterlab/pull/12349) ([@jtpio](https://github.com/jtpio)) +- Update to TypeScript 4.6 [#12348](https://github.com/jupyterlab/jupyterlab/pull/12348) ([@jtpio](https://github.com/jtpio)) +- [pre-commit.ci] pre-commit autoupdate [#12343](https://github.com/jupyterlab/jupyterlab/pull/12343) ([@pre-commit-ci](https://github.com/pre-commit-ci)) +- Remove the CI workflow for flaky tests [#12341](https://github.com/jupyterlab/jupyterlab/pull/12341) ([@jtpio](https://github.com/jtpio)) +- Disable `fail-fast` for the check release workflow [#12339](https://github.com/jupyterlab/jupyterlab/pull/12339) ([@jtpio](https://github.com/jtpio)) +- Use y-py 0.3.0 [#12326](https://github.com/jupyterlab/jupyterlab/pull/12326) ([@davidbrochart](https://github.com/davidbrochart)) + +### Documentation improvements + +- Fix typo: `exitOnUncaughtException` in `@jupyterlab/buildutils` [#12444](https://github.com/jupyterlab/jupyterlab/pull/12444) ([@jtpio](https://github.com/jtpio)) +- Removes FileEditorCodeWrapper [#12439](https://github.com/jupyterlab/jupyterlab/pull/12439) ([@hbcarlos](https://github.com/hbcarlos)) +- Update to webpack 5.72 [#12423](https://github.com/jupyterlab/jupyterlab/pull/12423) ([@jtpio](https://github.com/jtpio)) +- Fix documentation links [#12407](https://github.com/jupyterlab/jupyterlab/pull/12407) ([@fcollonval](https://github.com/fcollonval)) +- Deprecate FileEditorCodeWrapper [#12381](https://github.com/jupyterlab/jupyterlab/pull/12381) ([@hbcarlos](https://github.com/hbcarlos)) +- Update command to `pip install -e ".[test]"` in the contribution documentation [#12373](https://github.com/jupyterlab/jupyterlab/pull/12373) ([@jtpio](https://github.com/jtpio)) +- Fix broken PR link in changelog [#12334](https://github.com/jupyterlab/jupyterlab/pull/12334) ([@krassowski](https://github.com/krassowski)) +- Add postmortems section to RELEASE.md [#12327](https://github.com/jupyterlab/jupyterlab/pull/12327) ([@jtpio](https://github.com/jtpio)) +- Simplify galata import by proxying `expect` [#12311](https://github.com/jupyterlab/jupyterlab/pull/12311) ([@fcollonval](https://github.com/fcollonval)) +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@jweill-aws](https://github.com/jweill-aws)) + +### API and Breaking Changes + +- Fix typo: `exitOnUncaughtException` in `@jupyterlab/buildutils` [#12444](https://github.com/jupyterlab/jupyterlab/pull/12444) ([@jtpio](https://github.com/jtpio)) +- Removes FileEditorCodeWrapper [#12439](https://github.com/jupyterlab/jupyterlab/pull/12439) ([@hbcarlos](https://github.com/hbcarlos)) +- Add parent header to input reply kernel message [#12376](https://github.com/jupyterlab/jupyterlab/pull/12376) ([@davidbrochart](https://github.com/davidbrochart)) +- Provide `IDocumentManager` in a separate plugin [#12349](https://github.com/jupyterlab/jupyterlab/pull/12349) ([@jtpio](https://github.com/jtpio)) + +### 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-03-31&to=2022-04-25&type=c)) + +[@a3626a](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aa3626a+updated%3A2022-03-31..2022-04-25&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-03-31..2022-04-25&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-03-31..2022-04-25&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-03-31..2022-04-25&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2022-03-31..2022-04-25&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-03-31..2022-04-25&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-03-31..2022-04-25&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-03-31..2022-04-25&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-03-31..2022-04-25&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2022-03-31..2022-04-25&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-03-31..2022-04-25&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-31..2022-04-25&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-03-31..2022-04-25&type=Issues) | [@galathinius](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agalathinius+updated%3A2022-03-31..2022-04-25&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-31..2022-04-25&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-03-31..2022-04-25&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-03-31..2022-04-25&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-31..2022-04-25&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-31..2022-04-25&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-03-31..2022-04-25&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-03-31..2022-04-25&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2022-03-31..2022-04-25&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-03-31..2022-04-25&type=Issues) | [@max-schaefer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amax-schaefer+updated%3A2022-03-31..2022-04-25&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-03-31..2022-04-25&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-03-31..2022-04-25&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apre-commit-ci+updated%3A2022-03-31..2022-04-25&type=Issues) | [@Pugio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3APugio+updated%3A2022-03-31..2022-04-25&type=Issues) | [@rccern](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arccern+updated%3A2022-03-31..2022-04-25&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-03-31..2022-04-25&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-03-31..2022-04-25&type=Issues) | [@xiaochen-db](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Axiaochen-db+updated%3A2022-03-31..2022-04-25&type=Issues) | [@yangql176](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayangql176+updated%3A2022-03-31..2022-04-25&type=Issues) + +## 4.0.0a23 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a22...6a5e1d47e1bc0d40d3850ad8aae1b32079846a0c)) + +### Enhancements made + +- Remove Yjs room locks [#12288](https://github.com/jupyterlab/jupyterlab/pull/12288) ([@davidbrochart](https://github.com/davidbrochart)) +- Adds preferKernel option to JupyterLab code [#12260](https://github.com/jupyterlab/jupyterlab/pull/12260) ([@jweill-aws](https://github.com/jweill-aws)) +- Customize the file browser toolbar via the settings [#12281](https://github.com/jupyterlab/jupyterlab/pull/12281) ([@fcollonval](https://github.com/fcollonval)) +- Show kernel name on restart to avoid data loss on misclick [#12241](https://github.com/jupyterlab/jupyterlab/pull/12241) ([@krassowski](https://github.com/krassowski)) +- Ignore auto-generated `.ipynb_checkpoints` directories [#12239](https://github.com/jupyterlab/jupyterlab/pull/12239) ([@krassowski](https://github.com/krassowski)) +- Add aria progressbar role and data-status for testing in extensions [#12238](https://github.com/jupyterlab/jupyterlab/pull/12238) ([@krassowski](https://github.com/krassowski)) +- Add a "New Tab" button that opens the launcher [#12195](https://github.com/jupyterlab/jupyterlab/pull/12195) ([@ajbozarth](https://github.com/ajbozarth)) +- add "Toggle Contextual Help" command [#12091](https://github.com/jupyterlab/jupyterlab/pull/12091) ([@Josh0823](https://github.com/jgeden)) +- Save document from the backend using y-py [#11599](https://github.com/jupyterlab/jupyterlab/pull/11599) ([@davidbrochart](https://github.com/davidbrochart)) + +### Bugs fixed + +- Use Black 22.3.0 [#12285](https://github.com/jupyterlab/jupyterlab/pull/12285) ([@davidbrochart](https://github.com/davidbrochart)) +- Allow linear and radial gradient [#12276](https://github.com/jupyterlab/jupyterlab/pull/12276) ([@krassowski](https://github.com/krassowski)) +- Use css variable for font size. [#12255](https://github.com/jupyterlab/jupyterlab/pull/12255) ([@Carreau](https://github.com/Carreau)) +- Don't rely on search results to filter installed extension [#12249](https://github.com/jupyterlab/jupyterlab/pull/12249) ([@fcollonval](https://github.com/fcollonval)) +- Fix settings with `null` default not getting marked as modified [#12240](https://github.com/jupyterlab/jupyterlab/pull/12240) ([@krassowski](https://github.com/krassowski)) +- fixes directory not found error when preferred_dir is set [#12220](https://github.com/jupyterlab/jupyterlab/pull/12220) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Filter settings with `app.hasPlugin()` [#11938](https://github.com/jupyterlab/jupyterlab/pull/11938) ([@jtpio](https://github.com/jtpio)) + +### Maintenance and upkeep improvements + +- Fix usage of pre-commit-ci [#12304](https://github.com/jupyterlab/jupyterlab/pull/12304) ([@blink1073](https://github.com/blink1073)) +- Fix documentation snapshots [#12301](https://github.com/jupyterlab/jupyterlab/pull/12301) ([@fcollonval](https://github.com/fcollonval)) +- Add flake8 rules and update files [#12291](https://github.com/jupyterlab/jupyterlab/pull/12291) ([@blink1073](https://github.com/blink1073)) +- Add git-blame-ignore-revs file [#12290](https://github.com/jupyterlab/jupyterlab/pull/12290) ([@blink1073](https://github.com/blink1073)) +- Use pre-commit [#12279](https://github.com/jupyterlab/jupyterlab/pull/12279) ([@blink1073](https://github.com/blink1073)) +- Bump minimist from 1.2.5 to 1.2.6 [#12266](https://github.com/jupyterlab/jupyterlab/pull/12266) ([@dependabot](https://github.com/dependabot)) +- Stop using py.test [#12262](https://github.com/jupyterlab/jupyterlab/pull/12262) ([@fcollonval](https://github.com/fcollonval)) +- Re-align version for `@jupyterlab/markedparser-extension` [#12247](https://github.com/jupyterlab/jupyterlab/pull/12247) ([@jtpio](https://github.com/jtpio)) +- Make `IStatusBar` optional in the plugin providing `IPositionModel` [#12232](https://github.com/jupyterlab/jupyterlab/pull/12232) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Update `NotebookApp` to `ServerApp` in the contributing docs [#12309](https://github.com/jupyterlab/jupyterlab/pull/12309) ([@jtpio](https://github.com/jtpio)) +- Remove Yjs room locks [#12288](https://github.com/jupyterlab/jupyterlab/pull/12288) ([@davidbrochart](https://github.com/davidbrochart)) +- Customize the file browser toolbar via the settings [#12281](https://github.com/jupyterlab/jupyterlab/pull/12281) ([@fcollonval](https://github.com/fcollonval)) +- Use pre-commit [#12279](https://github.com/jupyterlab/jupyterlab/pull/12279) ([@blink1073](https://github.com/blink1073)) +- Stop using py.test [#12262](https://github.com/jupyterlab/jupyterlab/pull/12262) ([@fcollonval](https://github.com/fcollonval)) +- Update links to create new issues in README.md [#12257](https://github.com/jupyterlab/jupyterlab/pull/12257) ([@jtpio](https://github.com/jtpio)) +- Update link to `jupyterlab-some-package` in docs [#12248](https://github.com/jupyterlab/jupyterlab/pull/12248) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Remove Yjs room locks [#12288](https://github.com/jupyterlab/jupyterlab/pull/12288) ([@davidbrochart](https://github.com/davidbrochart)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-03-18&to=2022-03-31&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-03-18..2022-03-31&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2022-03-18..2022-03-31&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2022-03-18..2022-03-31&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2022-03-18..2022-03-31&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-03-18..2022-03-31&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ACarreau+updated%3A2022-03-18..2022-03-31&type=Issues) | [@damianavila](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adamianavila+updated%3A2022-03-18..2022-03-31&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-03-18..2022-03-31&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-03-18..2022-03-31&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-03-18..2022-03-31&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-18..2022-03-31&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-18..2022-03-31&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-03-18..2022-03-31&type=Issues) | [@Josh0823](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJosh0823+updated%3A2022-03-18..2022-03-31&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-18..2022-03-31&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-18..2022-03-31&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-03-18..2022-03-31&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-03-18..2022-03-31&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-03-18..2022-03-31&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-03-18..2022-03-31&type=Issues) + +## 4.0.0a22 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a21...0040f2649c77af0251b8c8f73aea91c26c3960c5)) + +### Bugs fixed + +- 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 [#12208](https://github.com/jupyterlab/jupyterlab/pull/12208) ([@blink1073](https://github.com/blink1073)) +- Remove use of ipython_genutils [#12202](https://github.com/jupyterlab/jupyterlab/pull/12202) ([@blink1073](https://github.com/blink1073)) + +### Maintenance and upkeep improvements + +- Inline `expected_http_error` function from `jupyterlab_server.tests` [#12228](https://github.com/jupyterlab/jupyterlab/pull/12228) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Update command in Performance Testing to use the right option [#12215](https://github.com/jupyterlab/jupyterlab/pull/12215) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-03-11&to=2022-03-18&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-03-11..2022-03-18&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-03-11..2022-03-18&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-03-11..2022-03-18&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-03-11..2022-03-18&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-03-11..2022-03-18&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-03-11..2022-03-18&type=Issues) + +## 4.0.0a21 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a20...d7f1704307c2e345f247e1a411bdbae50f2a5708)) + +### Enhancements made + +- Export KernelConnection [#12156](https://github.com/jupyterlab/jupyterlab/pull/12156) ([@tkrabel-db](https://github.com/tkrabel-db)) +- Document search debounce time via setting [#12097](https://github.com/jupyterlab/jupyterlab/pull/12097) ([@echarles](https://github.com/echarles)) +- Extract markdown parser in its own plugin. [#11971](https://github.com/jupyterlab/jupyterlab/pull/11971) ([@fcollonval](https://github.com/fcollonval)) +- Protocol alignment [#11841](https://github.com/jupyterlab/jupyterlab/pull/11841) ([@davidbrochart](https://github.com/davidbrochart)) +- Add users colors to the theme [#11703](https://github.com/jupyterlab/jupyterlab/pull/11703) ([@hbcarlos](https://github.com/hbcarlos)) + +### Bugs fixed + +- Update docstring in the user model [#12175](https://github.com/jupyterlab/jupyterlab/pull/12175) ([@hbcarlos](https://github.com/hbcarlos)) +- Typo in ShortcutItem component [#12161](https://github.com/jupyterlab/jupyterlab/pull/12161) ([@sparanoid](https://github.com/sparanoid)) +- Correct the set item logic of `CodeCellModel.onModelDBOutputsChange` [#12147](https://github.com/jupyterlab/jupyterlab/pull/12147) ([@trungleduc](https://github.com/trungleduc)) +- Build UMD module for @jupyterlab/services [#12141](https://github.com/jupyterlab/jupyterlab/pull/12141) ([@fcollonval](https://github.com/fcollonval)) +- Select kernel text (when open a no kernal .ipynb file) is not translated correctly (#12133) [#12135](https://github.com/jupyterlab/jupyterlab/pull/12135) ([@yangql176](https://github.com/yangql176)) +- Remove duplicated shortcuts [#12122](https://github.com/jupyterlab/jupyterlab/pull/12122) ([@fcollonval](https://github.com/fcollonval)) +- Opening keyboard shortcuts UI result in "destruction" of shortcut settings [#12112](https://github.com/jupyterlab/jupyterlab/pull/12112) ([@fcollonval](https://github.com/fcollonval)) + +### Maintenance and upkeep improvements + +- Freeze content last modified time for documentation tabs menu [#12183](https://github.com/jupyterlab/jupyterlab/pull/12183) ([@fcollonval](https://github.com/fcollonval)) +- Bump url-parse from 1.5.8 to 1.5.9 [#12144](https://github.com/jupyterlab/jupyterlab/pull/12144) ([@dependabot](https://github.com/dependabot)) +- Fix typos in `kernel-status` plugins [#12130](https://github.com/jupyterlab/jupyterlab/pull/12130) ([@jtpio](https://github.com/jtpio)) +- Bump url-parse from 1.5.6 to 1.5.8 [#12128](https://github.com/jupyterlab/jupyterlab/pull/12128) ([@dependabot](https://github.com/dependabot)) +- Set left sidebar width through mouse motion [#12123](https://github.com/jupyterlab/jupyterlab/pull/12123) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Update docstring in the user model [#12175](https://github.com/jupyterlab/jupyterlab/pull/12175) ([@hbcarlos](https://github.com/hbcarlos)) +- Document search debounce time via setting [#12097](https://github.com/jupyterlab/jupyterlab/pull/12097) ([@echarles](https://github.com/echarles)) +- Document the JupyterLab Release Process [#12074](https://github.com/jupyterlab/jupyterlab/pull/12074) ([@jtpio](https://github.com/jtpio)) +- Extract markdown parser in its own plugin. [#11971](https://github.com/jupyterlab/jupyterlab/pull/11971) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-02-24&to=2022-03-11&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-02-24..2022-03-11&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-02-24..2022-03-11&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-02-24..2022-03-11&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-02-24..2022-03-11&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2022-02-24..2022-03-11&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-02-24..2022-03-11&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-02-24..2022-03-11&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-02-24..2022-03-11&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-02-24..2022-03-11&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-02-24..2022-03-11&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-02-24..2022-03-11&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-02-24..2022-03-11&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2022-02-24..2022-03-11&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-02-24..2022-03-11&type=Issues) | [@sparanoid](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asparanoid+updated%3A2022-02-24..2022-03-11&type=Issues) | [@tkrabel-db](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atkrabel-db+updated%3A2022-02-24..2022-03-11&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-02-24..2022-03-11&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-02-24..2022-03-11&type=Issues) | [@yangql176](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayangql176+updated%3A2022-02-24..2022-03-11&type=Issues) + +## 4.0.0a20 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a19...3468cc4990c2d0f0b3e3381c284a59a2e13f2d55)) + +### Enhancements made + +- Settings UI gives an unreadable JSON dump [#12064](https://github.com/jupyterlab/jupyterlab/pull/12064) ([@fcollonval](https://github.com/fcollonval)) +- Polish settings editor [#12045](https://github.com/jupyterlab/jupyterlab/pull/12045) ([@krassowski](https://github.com/krassowski)) +- Debounce kernel sources filter [#12030](https://github.com/jupyterlab/jupyterlab/pull/12030) ([@echarles](https://github.com/echarles)) +- show pause on exception button when not available and change caption â€Ļ [#12005](https://github.com/jupyterlab/jupyterlab/pull/12005) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Fix contrast in dark theme of settings editor [#12004](https://github.com/jupyterlab/jupyterlab/pull/12004) ([@krassowski](https://github.com/krassowski)) +- Update completer part 2 [#11969](https://github.com/jupyterlab/jupyterlab/pull/11969) ([@trungleduc](https://github.com/trungleduc)) +- Support dynamic toolbar definition [#11963](https://github.com/jupyterlab/jupyterlab/pull/11963) ([@fcollonval](https://github.com/fcollonval)) +- Fix for kernel reconnect [#11952](https://github.com/jupyterlab/jupyterlab/pull/11952) ([@3coins](https://github.com/3coins)) +- Add additional `Accel Enter` keyboard shortcuts for the `notebook:run-cell` command [#11942](https://github.com/jupyterlab/jupyterlab/pull/11942) ([@jtpio](https://github.com/jtpio)) +- Explicitly specifies triageLabel parameter [#11912](https://github.com/jupyterlab/jupyterlab/pull/11912) ([@jweill-aws](https://github.com/jweill-aws)) +- Add spacer widget via `app.shell` instead of `ILabShell` [#11900](https://github.com/jupyterlab/jupyterlab/pull/11900) ([@jtpio](https://github.com/jtpio)) +- Add startMode setting to define the startup mode [#11881](https://github.com/jupyterlab/jupyterlab/pull/11881) ([@echarles](https://github.com/echarles)) +- Add side-by-side margin override in the notebookConfig [#11880](https://github.com/jupyterlab/jupyterlab/pull/11880) ([@echarles](https://github.com/echarles)) +- Pause on exception [#11752](https://github.com/jupyterlab/jupyterlab/pull/11752) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Increase color contrast in input boxes [#11658](https://github.com/jupyterlab/jupyterlab/pull/11658) ([@isabela-pf](https://github.com/isabela-pf)) +- Show the kernel sources as a debugger tab and allow the user to break in kernel sources [#11566](https://github.com/jupyterlab/jupyterlab/pull/11566) ([@echarles](https://github.com/echarles)) +- Refactor status bar [#11450](https://github.com/jupyterlab/jupyterlab/pull/11450) ([@fcollonval](https://github.com/fcollonval)) +- Add settings UI [#11079](https://github.com/jupyterlab/jupyterlab/pull/11079) ([@marthacryan](https://github.com/marthacryan)) +- Enable not showing editor for read-only Markdown cells [#10956](https://github.com/jupyterlab/jupyterlab/pull/10956) ([@krassowska](https://github.com/krassowska)) + +### Bugs fixed + +- Improve toggled button styles in debugger. [#12110](https://github.com/jupyterlab/jupyterlab/pull/12110) ([@fcollonval](https://github.com/fcollonval)) +- Fix error rendering in Advanced Settings Editor [#12107](https://github.com/jupyterlab/jupyterlab/pull/12107) ([@krassowski](https://github.com/krassowski)) +- Remove toolbar factory setting trick in the tests [#12096](https://github.com/jupyterlab/jupyterlab/pull/12096) ([@jtpio](https://github.com/jtpio)) +- update status to unkown when kernel is shutdown from running kernels tab [#12083](https://github.com/jupyterlab/jupyterlab/pull/12083) ([@akshaychitneni](https://github.com/akshaychitneni)) +- Log error on open document widget. [#12080](https://github.com/jupyterlab/jupyterlab/pull/12080) ([@trungleduc](https://github.com/trungleduc)) +- Handle shutdown error [#12048](https://github.com/jupyterlab/jupyterlab/pull/12048) ([@Zsailer](https://github.com/Zsailer)) +- Update snapshot following settings editor new wording [#12035](https://github.com/jupyterlab/jupyterlab/pull/12035) ([@fcollonval](https://github.com/fcollonval)) +- use path-like comparison in initialize_templates() [#12024](https://github.com/jupyterlab/jupyterlab/pull/12024) ([@kellyyke](https://github.com/kellyyke)) +- Adjust z-index of execution progress tooltip [#11973](https://github.com/jupyterlab/jupyterlab/pull/11973) ([@Sync271](https://github.com/Sync271)) +- Add legacy editor to same palette category [#11978](https://github.com/jupyterlab/jupyterlab/pull/11978) ([@fcollonval](https://github.com/fcollonval)) +- Fix misaligned icon and checkbox of setting editor [#11976](https://github.com/jupyterlab/jupyterlab/pull/11976) ([@trungleduc](https://github.com/trungleduc)) +- Fix the debug modules model [#11967](https://github.com/jupyterlab/jupyterlab/pull/11967) ([@echarles](https://github.com/echarles)) +- Fix autocomplete in console [#11949](https://github.com/jupyterlab/jupyterlab/pull/11949) ([@fcollonval](https://github.com/fcollonval)) +- fix(docprovider): fix issue with empty notebook [#11901](https://github.com/jupyterlab/jupyterlab/pull/11901) ([@entropitor](https://github.com/entropitor)) +- ensure a single modal is opened in case of time conflict savings [#11883](https://github.com/jupyterlab/jupyterlab/pull/11883) ([@echarles](https://github.com/echarles)) +- Add percent decoding to `username` & `initials` [#11852](https://github.com/jupyterlab/jupyterlab/pull/11852) ([@HoseonRyu](https://github.com/HoseonRyu)) +- Update reference snapshot for the completer UI test [#11844](https://github.com/jupyterlab/jupyterlab/pull/11844) ([@jtpio](https://github.com/jtpio)) +- Specify an output hash function for Galata [#11830](https://github.com/jupyterlab/jupyterlab/pull/11830) ([@jasongrout](https://github.com/jasongrout)) +- Trust dialog link styling, text changes [#11827](https://github.com/jupyterlab/jupyterlab/pull/11827) ([@jweill-aws](https://github.com/jweill-aws)) +- Fixes Ctrl+Shift+ArrowLeft/Right shortcuts edit mode [#11818](https://github.com/jupyterlab/jupyterlab/pull/11818) ([@schmidi314](https://github.com/schmidi314)) +- Restore line number state when stopping debugger [#11768](https://github.com/jupyterlab/jupyterlab/pull/11768) ([@fcollonval](https://github.com/fcollonval)) + +### Maintenance and upkeep improvements + +- Bump url-parse from 1.5.4 to 1.5.6 [#12076](https://github.com/jupyterlab/jupyterlab/pull/12076) ([@dependabot](https://github.com/dependabot)) +- Bump follow-redirects from 1.14.7 to 1.14.8 [#12050](https://github.com/jupyterlab/jupyterlab/pull/12050) ([@dependabot](https://github.com/dependabot)) +- Parse URL parameters in user model [#12046](https://github.com/jupyterlab/jupyterlab/pull/12046) ([@hbcarlos](https://github.com/hbcarlos)) +- Update to `react-json-tree@^0.16.1` [#12044](https://github.com/jupyterlab/jupyterlab/pull/12044) ([@jtpio](https://github.com/jtpio)) +- Stabilize documentation CI tests [#12043](https://github.com/jupyterlab/jupyterlab/pull/12043) ([@fcollonval](https://github.com/fcollonval)) +- Update Playwright snapshots from PR comments [#12040](https://github.com/jupyterlab/jupyterlab/pull/12040) ([@fcollonval](https://github.com/fcollonval)) +- Mehmet employer update [#12033](https://github.com/jupyterlab/jupyterlab/pull/12033) ([@mbektas](https://github.com/mbektas)) +- Bump simple-get from 3.1.0 to 3.1.1 [#12010](https://github.com/jupyterlab/jupyterlab/pull/12010) ([@dependabot](https://github.com/dependabot)) +- [squash] Apply most auto-fixable stylelint rules [#11993](https://github.com/jupyterlab/jupyterlab/pull/11993) ([@bollwyvl](https://github.com/bollwyvl)) +- Bump json-schema from 0.3.0 to 0.4.0 [#11974](https://github.com/jupyterlab/jupyterlab/pull/11974) ([@dependabot](https://github.com/dependabot)) +- Fix General Welcome documentation test [#11961](https://github.com/jupyterlab/jupyterlab/pull/11961) ([@fcollonval](https://github.com/fcollonval)) +- Remove tslint comment and move `Token` to `tokens.ts` [#11955](https://github.com/jupyterlab/jupyterlab/pull/11955) ([@fcollonval](https://github.com/fcollonval)) +- Adopt stylelint and apply initial rules [#11944](https://github.com/jupyterlab/jupyterlab/pull/11944) ([@bollwyvl](https://github.com/bollwyvl)) +- Bump node-fetch from 2.6.1 to 2.6.7 [#11918](https://github.com/jupyterlab/jupyterlab/pull/11918) ([@dependabot](https://github.com/dependabot)) +- Bump nanoid from 3.1.23 to 3.2.0 [#11914](https://github.com/jupyterlab/jupyterlab/pull/11914) ([@dependabot](https://github.com/dependabot)) +- Remove unused `isInit` param in `sessionContext.changeKernel()` [#11907](https://github.com/jupyterlab/jupyterlab/pull/11907) ([@jtpio](https://github.com/jtpio)) +- Fix plugin id for the toolbar registry plugin [#11899](https://github.com/jupyterlab/jupyterlab/pull/11899) ([@jtpio](https://github.com/jtpio)) +- Drop `nbclassic`, depend on `notebook_shim` [#11894](https://github.com/jupyterlab/jupyterlab/pull/11894) ([@jtpio](https://github.com/jtpio)) +- simplify validateMimeValue regex [#11890](https://github.com/jupyterlab/jupyterlab/pull/11890) ([@minrk](https://github.com/minrk)) +- Bump marked from 2.1.3 to 4.0.10 [#11879](https://github.com/jupyterlab/jupyterlab/pull/11879) ([@dependabot](https://github.com/dependabot)) +- Bump follow-redirects from 1.14.1 to 1.14.7 [#11864](https://github.com/jupyterlab/jupyterlab/pull/11864) ([@dependabot](https://github.com/dependabot)) +- Update to the latest lumino [#11823](https://github.com/jupyterlab/jupyterlab/pull/11823) ([@hbcarlos](https://github.com/hbcarlos)) +- Use playwright to generate documentation screenshots [#11821](https://github.com/jupyterlab/jupyterlab/pull/11821) ([@fcollonval](https://github.com/fcollonval)) +- Remove `url` dependency from `@jupyterlab/apputils` [#11813](https://github.com/jupyterlab/jupyterlab/pull/11813) ([@jtpio](https://github.com/jtpio)) +- Ensure federated example resolutions [#11714](https://github.com/jupyterlab/jupyterlab/pull/11714) ([@jtpio](https://github.com/jtpio)) +- Optional sessionContext for ConsoleHistory [#9975](https://github.com/jupyterlab/jupyterlab/pull/9975) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Pull request must target master [#12088](https://github.com/jupyterlab/jupyterlab/pull/12088) ([@fcollonval](https://github.com/fcollonval)) +- Fix anchors and myst configuration [#12063](https://github.com/jupyterlab/jupyterlab/pull/12063) ([@fcollonval](https://github.com/fcollonval)) +- Update Playwright snapshots from PR comments [#12040](https://github.com/jupyterlab/jupyterlab/pull/12040) ([@fcollonval](https://github.com/fcollonval)) +- Mehmet employer update [#12033](https://github.com/jupyterlab/jupyterlab/pull/12033) ([@mbektas](https://github.com/mbektas)) +- docs: fix shell command with unquoted '>' [#12002](https://github.com/jupyterlab/jupyterlab/pull/12002) ([@ErikBjare](https://github.com/ErikBjare)) +- Fix a bumpversion example in release markdown [#12006](https://github.com/jupyterlab/jupyterlab/pull/12006) ([@echarles](https://github.com/echarles)) +- [squash] Apply most auto-fixable stylelint rules [#11993](https://github.com/jupyterlab/jupyterlab/pull/11993) ([@bollwyvl](https://github.com/bollwyvl)) +- Remove tslint comment and move `Token` to `tokens.ts` [#11955](https://github.com/jupyterlab/jupyterlab/pull/11955) ([@fcollonval](https://github.com/fcollonval)) +- Update several extensions readme files to delete old content. [#11947](https://github.com/jupyterlab/jupyterlab/pull/11947) ([@jasongrout](https://github.com/jasongrout)) +- Adopt stylelint and apply initial rules [#11944](https://github.com/jupyterlab/jupyterlab/pull/11944) ([@bollwyvl](https://github.com/bollwyvl)) +- Remove theme cookiecutter from the docs [#11928](https://github.com/jupyterlab/jupyterlab/pull/11928) ([@jtpio](https://github.com/jtpio)) +- Updates code, documentation to use new standard terms for cell output [#11904](https://github.com/jupyterlab/jupyterlab/pull/11904) ([@jweill-aws](https://github.com/jweill-aws)) +- Drop `nbclassic`, depend on `notebook_shim` [#11894](https://github.com/jupyterlab/jupyterlab/pull/11894) ([@jtpio](https://github.com/jtpio)) +- DOCS: Remove custom icon link template [#11882](https://github.com/jupyterlab/jupyterlab/pull/11882) ([@choldgraf](https://github.com/choldgraf)) +- Add the `3.3.0a1` Changelog Entry [#11860](https://github.com/jupyterlab/jupyterlab/pull/11860) ([@jtpio](https://github.com/jtpio)) +- Add missing `v3.2` title to the changelog [#11859](https://github.com/jupyterlab/jupyterlab/pull/11859) ([@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)) +- Use playwright to generate documentation screenshots [#11821](https://github.com/jupyterlab/jupyterlab/pull/11821) ([@fcollonval](https://github.com/fcollonval)) +- DOCS: Convert theme to pydata-sphinx-theme [#11803](https://github.com/jupyterlab/jupyterlab/pull/11803) ([@choldgraf](https://github.com/choldgraf)) +- Refactor completer and completer-extension package [#11795](https://github.com/jupyterlab/jupyterlab/pull/11795) ([@trungleduc](https://github.com/trungleduc)) +- Refactor status bar [#11450](https://github.com/jupyterlab/jupyterlab/pull/11450) ([@fcollonval](https://github.com/fcollonval)) +- Optional sessionContext for ConsoleHistory [#9975](https://github.com/jupyterlab/jupyterlab/pull/9975) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Drop `nbclassic`, depend on `notebook_shim` [#11894](https://github.com/jupyterlab/jupyterlab/pull/11894) ([@jtpio](https://github.com/jtpio)) +- Refactor completer and completer-extension package [#11795](https://github.com/jupyterlab/jupyterlab/pull/11795) ([@trungleduc](https://github.com/trungleduc)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-01-12&to=2022-02-24&type=c)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2022-01-12..2022-02-24&type=Issues) | [@akshaychitneni](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aakshaychitneni+updated%3A2022-01-12..2022-02-24&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2022-01-12..2022-02-24&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-01-12..2022-02-24&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-01-12..2022-02-24&type=Issues) | [@choldgraf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Acholdgraf+updated%3A2022-01-12..2022-02-24&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-01-12..2022-02-24&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2022-01-12..2022-02-24&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-01-12..2022-02-24&type=Issues) | [@entropitor](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aentropitor+updated%3A2022-01-12..2022-02-24&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-01-12..2022-02-24&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-01-12..2022-02-24&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-01-12..2022-02-24&type=Issues) | [@HoseonRyu](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AHoseonRyu+updated%3A2022-01-12..2022-02-24&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2022-01-12..2022-02-24&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2022-01-12..2022-02-24&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2022-01-12..2022-02-24&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-01-12..2022-02-24&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-01-12..2022-02-24&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-01-12..2022-02-24&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-01-12..2022-02-24&type=Issues) | [@kellyyke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akellyyke+updated%3A2022-01-12..2022-02-24&type=Issues) | [@krassowska](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowska+updated%3A2022-01-12..2022-02-24&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-01-12..2022-02-24&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2022-01-12..2022-02-24&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2022-01-12..2022-02-24&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-01-12..2022-02-24&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-01-12..2022-02-24&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aminrk+updated%3A2022-01-12..2022-02-24&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2022-01-12..2022-02-24&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2022-01-12..2022-02-24&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2022-01-12..2022-02-24&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2022-01-12..2022-02-24&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-01-12..2022-02-24&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2022-01-12..2022-02-24&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2022-01-12..2022-02-24&type=Issues) + +## 4.0.0a19 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a18...fc3f1f2f75f4bb3c8df0f3fa9f8508f17d532907)) + +### Enhancements made + +- Mentions pip3 for macOS users in docs [#11816](https://github.com/jupyterlab/jupyterlab/pull/11816) ([@jweill-aws](https://github.com/jweill-aws)) +- Fix overlapped shadow for scrolling output cell [#11785](https://github.com/jupyterlab/jupyterlab/pull/11785) ([@thesinepainter](https://github.com/thesinepainter)) +- Drop familyName from the ICurrentUser interface [#11774](https://github.com/jupyterlab/jupyterlab/pull/11774) ([@hbcarlos](https://github.com/hbcarlos)) +- List workspaces [#11730](https://github.com/jupyterlab/jupyterlab/pull/11730) ([@fcollonval](https://github.com/fcollonval)) +- Keyboard shortcuts related to collapsible headings [#11615](https://github.com/jupyterlab/jupyterlab/pull/11615) ([@schmidi314](https://github.com/schmidi314)) +- Update variable renderer panels [#11171](https://github.com/jupyterlab/jupyterlab/pull/11171) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Fix for Code Mirror width. Indentation changes made [#11814](https://github.com/jupyterlab/jupyterlab/pull/11814) ([@pree-T](https://github.com/pree-T)) +- Preserve breakpoint gutter when cells are moved. [#11766](https://github.com/jupyterlab/jupyterlab/pull/11766) ([@fcollonval](https://github.com/fcollonval)) + +### Maintenance and upkeep improvements + +- Update `vscode-debugprotocol` to `@vscode/debugprotocol` [#11812](https://github.com/jupyterlab/jupyterlab/pull/11812) ([@jtpio](https://github.com/jtpio)) +- Remove trailing slash from translations request [#11783](https://github.com/jupyterlab/jupyterlab/pull/11783) ([@davidbrochart](https://github.com/davidbrochart)) + +### Documentation improvements + +- Update trove classifier [#11819](https://github.com/jupyterlab/jupyterlab/pull/11819) ([@fcollonval](https://github.com/fcollonval)) +- Mentions pip3 for macOS users in docs [#11816](https://github.com/jupyterlab/jupyterlab/pull/11816) ([@jweill-aws](https://github.com/jweill-aws)) +- Keyboard shortcuts related to collapsible headings [#11615](https://github.com/jupyterlab/jupyterlab/pull/11615) ([@schmidi314](https://github.com/schmidi314)) + +### API and Breaking Changes + +- Keyboard shortcuts related to collapsible headings [#11615](https://github.com/jupyterlab/jupyterlab/pull/11615) ([@schmidi314](https://github.com/schmidi314)) +- Update variable renderer panels [#11171](https://github.com/jupyterlab/jupyterlab/pull/11171) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2022-01-04&to=2022-01-12&type=c)) + +[@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2022-01-04..2022-01-12&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2022-01-04..2022-01-12&type=Issues) | [@baggiponte](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abaggiponte+updated%3A2022-01-04..2022-01-12&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2022-01-04..2022-01-12&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-01-04..2022-01-12&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-01-04..2022-01-12&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-01-04..2022-01-12&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2022-01-04..2022-01-12&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-01-04..2022-01-12&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2022-01-04..2022-01-12&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-01-04..2022-01-12&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-01-04..2022-01-12&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-01-04..2022-01-12&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-01-04..2022-01-12&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-01-04..2022-01-12&type=Issues) | [@pree-T](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apree-T+updated%3A2022-01-04..2022-01-12&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2022-01-04..2022-01-12&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2022-01-04..2022-01-12&type=Issues) | [@thesinepainter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athesinepainter+updated%3A2022-01-04..2022-01-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-01-04..2022-01-12&type=Issues) + +## 4.0.0a18 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a17...950ff2f44779f4a72433071ffee237e7e7bd84f1)) + +### Enhancements made + +- Remove `Install`, `Update` and `Uninstall` buttons from the extension manager UI [#11751](https://github.com/jupyterlab/jupyterlab/pull/11751) ([@jtpio](https://github.com/jtpio)) +- Add JSX CodeMirror mode [#11666](https://github.com/jupyterlab/jupyterlab/pull/11666) ([@krassowski](https://github.com/krassowski)) +- Move the top area spacer to a different plugin [#11654](https://github.com/jupyterlab/jupyterlab/pull/11654) ([@jtpio](https://github.com/jtpio)) +- Add `closeOnExit` terminal option [#11637](https://github.com/jupyterlab/jupyterlab/pull/11637) ([@davidbrochart](https://github.com/davidbrochart)) +- Remove leading slash from console path [#11626](https://github.com/jupyterlab/jupyterlab/pull/11626) ([@davidbrochart](https://github.com/davidbrochart)) +- Toggle side-by-side rendering for current notebook [#11608](https://github.com/jupyterlab/jupyterlab/pull/11608) ([@echarles](https://github.com/echarles)) +- Allow to link factory to file type when adding it [#11540](https://github.com/jupyterlab/jupyterlab/pull/11540) ([@fcollonval](https://github.com/fcollonval)) +- Use transform to quickly switch between tabs. [#11074](https://github.com/jupyterlab/jupyterlab/pull/11074) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Fix semantic wrap words command [#11767](https://github.com/jupyterlab/jupyterlab/pull/11767) ([@fcollonval](https://github.com/fcollonval)) +- Restore compact notebook layout on mobile [#11762](https://github.com/jupyterlab/jupyterlab/pull/11762) ([@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)) +- Fix handling of disabled extensions [#11744](https://github.com/jupyterlab/jupyterlab/pull/11744) ([@jtpio](https://github.com/jtpio)) +- Removing early bail out in ToC widget update [#11711](https://github.com/jupyterlab/jupyterlab/pull/11711) ([@schmidi314](https://github.com/schmidi314)) +- updates debugger icon css to work with white panel background [#11688](https://github.com/jupyterlab/jupyterlab/pull/11688) ([@andrewfulton9](https://github.com/andrewfulton9)) +- 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 + +- Remove the `jedi` pin on CI [#11771](https://github.com/jupyterlab/jupyterlab/pull/11771) ([@jtpio](https://github.com/jtpio)) +- Fix integrity failure on CI [#11770](https://github.com/jupyterlab/jupyterlab/pull/11770) ([@jtpio](https://github.com/jtpio)) +- Remove deprecated `KarmaTestApp` and `JestApp` [#11742](https://github.com/jupyterlab/jupyterlab/pull/11742) ([@jtpio](https://github.com/jtpio)) +- Remove the `Promise.allSettled` polyfill [#11741](https://github.com/jupyterlab/jupyterlab/pull/11741) ([@jtpio](https://github.com/jtpio)) +- Drop support for Python 3.6 [#11740](https://github.com/jupyterlab/jupyterlab/pull/11740) ([@jtpio](https://github.com/jtpio)) +- Update `lighthouse` dependency in `@jupyterlab/testutils` [#11739](https://github.com/jupyterlab/jupyterlab/pull/11739) ([@jtpio](https://github.com/jtpio)) +- Remove custom type definitions for `sort-package-json` [#11712](https://github.com/jupyterlab/jupyterlab/pull/11712) ([@jtpio](https://github.com/jtpio)) +- Update typedoc to `0.22.10` [#11707](https://github.com/jupyterlab/jupyterlab/pull/11707) ([@hbcarlos](https://github.com/hbcarlos)) +- Drop support for `externalExtensions` [#11705](https://github.com/jupyterlab/jupyterlab/pull/11705) ([@jtpio](https://github.com/jtpio)) +- Remove the `watch` dependency from the examples [#11697](https://github.com/jupyterlab/jupyterlab/pull/11697) ([@jtpio](https://github.com/jtpio)) +- Bump nth-check from 2.0.0 to 2.0.1 [#11695](https://github.com/jupyterlab/jupyterlab/pull/11695) ([@dependabot](https://github.com/dependabot)) +- Remove references to `blueprintjs` in `ensure-repo` [#11694](https://github.com/jupyterlab/jupyterlab/pull/11694) ([@jtpio](https://github.com/jtpio)) +- Remove the `add:sibling` script [#11685](https://github.com/jupyterlab/jupyterlab/pull/11685) ([@jtpio](https://github.com/jtpio)) +- Remove the `create:theme` script [#11683](https://github.com/jupyterlab/jupyterlab/pull/11683) ([@jtpio](https://github.com/jtpio)) +- Remove Storybook [#11649](https://github.com/jupyterlab/jupyterlab/pull/11649) ([@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)) +- pyproject.toml: clarify build system version [#11642](https://github.com/jupyterlab/jupyterlab/pull/11642) ([@adamjstewart](https://github.com/adamjstewart)) +- Add test for `benchmark.distributionChange` [#11573](https://github.com/jupyterlab/jupyterlab/pull/11573) ([@fcollonval](https://github.com/fcollonval)) +- Bump `url-parse~1.5.4` [#10755](https://github.com/jupyterlab/jupyterlab/pull/10755) ([@krassowski](https://github.com/krassowski)) + +### Documentation improvements + +- 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)) +- Use shields.io badge for Gitpod editor [#11750](https://github.com/jupyterlab/jupyterlab/pull/11750) ([@krassowski](https://github.com/krassowski)) +- Encourage new contributors to send draft PR over asking for permission [#11746](https://github.com/jupyterlab/jupyterlab/pull/11746) ([@krassowski](https://github.com/krassowski)) +- Remove deprecated `KarmaTestApp` and `JestApp` [#11742](https://github.com/jupyterlab/jupyterlab/pull/11742) ([@jtpio](https://github.com/jtpio)) +- Fix formatting in extension migration docs [#11706](https://github.com/jupyterlab/jupyterlab/pull/11706) ([@jtpio](https://github.com/jtpio)) +- Drop support for `externalExtensions` [#11705](https://github.com/jupyterlab/jupyterlab/pull/11705) ([@jtpio](https://github.com/jtpio)) +- Remove the `add:sibling` script [#11685](https://github.com/jupyterlab/jupyterlab/pull/11685) ([@jtpio](https://github.com/jtpio)) +- Remove the `create:theme` script [#11683](https://github.com/jupyterlab/jupyterlab/pull/11683) ([@jtpio](https://github.com/jtpio)) +- Make `ILayoutRestorer` optional in the extension tutorial [#11677](https://github.com/jupyterlab/jupyterlab/pull/11677) ([@jtpio](https://github.com/jtpio)) +- Fix changelog link [#11668](https://github.com/jupyterlab/jupyterlab/pull/11668) ([@krassowski](https://github.com/krassowski)) +- Triage documentation [#11661](https://github.com/jupyterlab/jupyterlab/pull/11661) ([@jweill-aws](https://github.com/jweill-aws)) +- Move the top area spacer to a different plugin [#11654](https://github.com/jupyterlab/jupyterlab/pull/11654) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Remove deprecated `KarmaTestApp` and `JestApp` [#11742](https://github.com/jupyterlab/jupyterlab/pull/11742) ([@jtpio](https://github.com/jtpio)) +- Remove the `add:sibling` script [#11685](https://github.com/jupyterlab/jupyterlab/pull/11685) ([@jtpio](https://github.com/jtpio)) +- Remove the `create:theme` script [#11683](https://github.com/jupyterlab/jupyterlab/pull/11683) ([@jtpio](https://github.com/jtpio)) +- Add `closeOnExit` terminal option [#11637](https://github.com/jupyterlab/jupyterlab/pull/11637) ([@davidbrochart](https://github.com/davidbrochart)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-12-09&to=2022-01-04&type=c)) + +[@adamjstewart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aadamjstewart+updated%3A2021-12-09..2022-01-04&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-12-09..2022-01-04&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-12-09..2022-01-04&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-12-09..2022-01-04&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2021-12-09..2022-01-04&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-12-09..2022-01-04&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-12-09..2022-01-04&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-12-09..2022-01-04&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-12-09..2022-01-04&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-12-09..2022-01-04&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-12-09..2022-01-04&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-12-09..2022-01-04&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-12-09..2022-01-04&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-12-09..2022-01-04&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-12-09..2022-01-04&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2021-12-09..2022-01-04&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-12-09..2022-01-04&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-12-09..2022-01-04&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-12-09..2022-01-04&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2021-12-09..2022-01-04&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-12-09..2022-01-04&type=Issues) + +## 4.0.0a17 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a16...969fa5d674931a89322d60c7e8c5bf80752f6cdd)) + +### Enhancements made + +- Specifying print CSS rules for notebooks [#11635](https://github.com/jupyterlab/jupyterlab/pull/11635) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Add a user package to represent the current connected user [#11443](https://github.com/jupyterlab/jupyterlab/pull/11443) ([@hbcarlos](https://github.com/hbcarlos)) + +### Bugs fixed + +- Fix menu items for toc [#11622](https://github.com/jupyterlab/jupyterlab/pull/11622) ([@fcollonval](https://github.com/fcollonval)) + +### Maintenance and upkeep improvements + +- Bump nth-check from 2.0.0 to 2.0.1 in /jupyterlab/staging [#11629](https://github.com/jupyterlab/jupyterlab/pull/11629) ([@dependabot](https://github.com/dependabot)) +- Update to TypeScript 4.5 [#11594](https://github.com/jupyterlab/jupyterlab/pull/11594) ([@jtpio](https://github.com/jtpio)) +- RTC shared model: Rename createCellFromType into createCellFromModel [#11538](https://github.com/jupyterlab/jupyterlab/pull/11538) ([@martinRenou](https://github.com/martinRenou)) +- Make `NotebookPanel._onSave` private [#10420](https://github.com/jupyterlab/jupyterlab/pull/10420) ([@jtpio](https://github.com/jtpio)) + +- Fix menu items for toc [#11622](https://github.com/jupyterlab/jupyterlab/pull/11622) ([@fcollonval](https://github.com/fcollonval)) +- RTC shared model: Rename createCellFromType into createCellFromModel [#11538](https://github.com/jupyterlab/jupyterlab/pull/11538) ([@martinRenou](https://github.com/martinRenou)) +- Add a user package to represent the current connected user [#11443](https://github.com/jupyterlab/jupyterlab/pull/11443) ([@hbcarlos](https://github.com/hbcarlos)) +- Make `NotebookPanel._onSave` private [#10420](https://github.com/jupyterlab/jupyterlab/pull/10420) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Fix menu items for toc [#11622](https://github.com/jupyterlab/jupyterlab/pull/11622) ([@fcollonval](https://github.com/fcollonval)) +- RTC shared model: Rename createCellFromType into createCellFromModel [#11538](https://github.com/jupyterlab/jupyterlab/pull/11538) ([@martinRenou](https://github.com/martinRenou)) +- Make `NotebookPanel._onSave` private [#10420](https://github.com/jupyterlab/jupyterlab/pull/10420) ([@jtpio](https://github.com/jtpio)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-12-07&to=2021-12-09&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-12-07..2021-12-09&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2021-12-07..2021-12-09&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-12-07..2021-12-09&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-12-07..2021-12-09&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-12-07..2021-12-09&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-12-07..2021-12-09&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-12-07..2021-12-09&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-12-07..2021-12-09&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-12-07..2021-12-09&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2021-12-07..2021-12-09&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-12-07..2021-12-09&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-12-07..2021-12-09&type=Issues) + +## 4.0.0a16 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a15...17cf5fcd5caf563a55b811e5df6377db612f6cd3)) + +### Enhancements made + +- Increase title width in simple mode [#11546](https://github.com/jupyterlab/jupyterlab/pull/11546) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- User defined default viewer take precedence for rendered factory [#11541](https://github.com/jupyterlab/jupyterlab/pull/11541) ([@fcollonval](https://github.com/fcollonval)) +- Add side-by-side rendering as global setting [#11533](https://github.com/jupyterlab/jupyterlab/pull/11533) ([@jess-x](https://github.com/jess-x)) +- Feature/optional hidden cells button (v2) [#11519](https://github.com/jupyterlab/jupyterlab/pull/11519) ([@schmidi314](https://github.com/schmidi314)) +- Attempt removing use of flexbox in the notebook DOM [#11508](https://github.com/jupyterlab/jupyterlab/pull/11508) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Tweak CSS for scrolled outputs [#11478](https://github.com/jupyterlab/jupyterlab/pull/11478) ([@jtpio](https://github.com/jtpio)) +- Recommend trying prebuilt extension version in the build failure dialog [#11476](https://github.com/jupyterlab/jupyterlab/pull/11476) ([@krassowski](https://github.com/krassowski)) +- Makes restorer parameter optional in toc-extension [#11445](https://github.com/jupyterlab/jupyterlab/pull/11445) ([@jweill-aws](https://github.com/jweill-aws)) +- perf: scroll active toc item into view [#11413](https://github.com/jupyterlab/jupyterlab/pull/11413) ([@skyetim](https://github.com/skyetim)) +- Set default ui font to `system-ui` [#11388](https://github.com/jupyterlab/jupyterlab/pull/11388) ([@jasongrout](https://github.com/jasongrout)) +- Add a command to open a file from a URL [#11387](https://github.com/jupyterlab/jupyterlab/pull/11387) ([@jtpio](https://github.com/jtpio)) +- Force semantic commands to use command [#11386](https://github.com/jupyterlab/jupyterlab/pull/11386) ([@fcollonval](https://github.com/fcollonval)) +- Creates a new accordion panel with toolbar in the ui-components package [#11369](https://github.com/jupyterlab/jupyterlab/pull/11369) ([@hbcarlos](https://github.com/hbcarlos)) +- Toc running cell indicator [#11356](https://github.com/jupyterlab/jupyterlab/pull/11356) ([@andrewfulton9](https://github.com/andrewfulton9)) + +### Bugs fixed + +- overrides.json definition takes precedence [#11610](https://github.com/jupyterlab/jupyterlab/pull/11610) ([@fcollonval](https://github.com/fcollonval)) +- Fix markdown benchmark snapshot [#11575](https://github.com/jupyterlab/jupyterlab/pull/11575) ([@fcollonval](https://github.com/fcollonval)) +- Increase notebook-cell margin in side-by-side mode [#11539](https://github.com/jupyterlab/jupyterlab/pull/11539) ([@jess-x](https://github.com/jess-x)) +- Cell YModel: Fix setAttachment method [#11529](https://github.com/jupyterlab/jupyterlab/pull/11529) ([@martinRenou](https://github.com/martinRenou)) +- Support file type extension with upper case [#11526](https://github.com/jupyterlab/jupyterlab/pull/11526) ([@fcollonval](https://github.com/fcollonval)) +- Sync dirty property between clients [#11525](https://github.com/jupyterlab/jupyterlab/pull/11525) ([@hbcarlos](https://github.com/hbcarlos)) +- Allow cross-file anchors with leading number [#11517](https://github.com/jupyterlab/jupyterlab/pull/11517) ([@loichuder](https://github.com/loichuder)) +- Update `sanitize-html` pin to `3.5.3` [#11510](https://github.com/jupyterlab/jupyterlab/pull/11510) ([@krassowski](https://github.com/krassowski)) +- Connecting toggleCollapsedSignal to handler right at creation of Markâ€Ļ [#11505](https://github.com/jupyterlab/jupyterlab/pull/11505) ([@schmidi314](https://github.com/schmidi314)) +- Update ModelDB metadata when switching the shared model [#11493](https://github.com/jupyterlab/jupyterlab/pull/11493) ([@hbcarlos](https://github.com/hbcarlos)) +- 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)) +- 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)) +- Only show the head of the outputs and ensure iopub outputs are correctly displayed [#11457](https://github.com/jupyterlab/jupyterlab/pull/11457) ([@echarles](https://github.com/echarles)) +- regenerate server connection settings for printing [#11454](https://github.com/jupyterlab/jupyterlab/pull/11454) ([@mbektas](https://github.com/mbektas)) +- Fix json schema for kernel status settings [#11451](https://github.com/jupyterlab/jupyterlab/pull/11451) ([@fcollonval](https://github.com/fcollonval)) +- 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)) +- Handle relative paths to `themePath` and `schemaDir` [#11427](https://github.com/jupyterlab/jupyterlab/pull/11427) ([@jtpio](https://github.com/jtpio)) + +### Maintenance and upkeep improvements + +- Fix Benchmark tests (revert #11607) [#11623](https://github.com/jupyterlab/jupyterlab/pull/11623) ([@0x2b3bfa0](https://github.com/0x2b3bfa0)) +- Benchmark tests broken following update of NodeJS in ubuntu image [#11607](https://github.com/jupyterlab/jupyterlab/pull/11607) ([@fcollonval](https://github.com/fcollonval)) +- Small issues on tests [#11605](https://github.com/jupyterlab/jupyterlab/pull/11605) ([@hbcarlos](https://github.com/hbcarlos)) +- Use `maintainer-tools` base setup action [#11595](https://github.com/jupyterlab/jupyterlab/pull/11595) ([@jtpio](https://github.com/jtpio)) +- Upgrade yarn to 1.22.17 [#11592](https://github.com/jupyterlab/jupyterlab/pull/11592) ([@jtpio](https://github.com/jtpio)) +- Remove `@types/webpack-env` from `ui-components` [#11587](https://github.com/jupyterlab/jupyterlab/pull/11587) ([@jtpio](https://github.com/jtpio)) +- Explicitly build JupyterLab in dev-mode [#11580](https://github.com/jupyterlab/jupyterlab/pull/11580) ([@fcollonval](https://github.com/fcollonval)) +- Revert "Temporary fix for release checker pinning vega-embed" [#11578](https://github.com/jupyterlab/jupyterlab/pull/11578) ([@fcollonval](https://github.com/fcollonval)) +- Update some dependencies [#11576](https://github.com/jupyterlab/jupyterlab/pull/11576) ([@jtpio](https://github.com/jtpio)) +- Fix markdown benchmark snapshot [#11575](https://github.com/jupyterlab/jupyterlab/pull/11575) ([@fcollonval](https://github.com/fcollonval)) +- Temporary fix for release checker pinning vega-embed [#11571](https://github.com/jupyterlab/jupyterlab/pull/11571) ([@fcollonval](https://github.com/fcollonval)) +- postcss 8.4.0 breaks integrity 2 CI test [#11552](https://github.com/jupyterlab/jupyterlab/pull/11552) ([@fcollonval](https://github.com/fcollonval)) +- Clean up Frontend Typings [#11537](https://github.com/jupyterlab/jupyterlab/pull/11537) ([@jtpio](https://github.com/jtpio)) +- Bump tar from 4.4.13 to 4.4.19 [#11536](https://github.com/jupyterlab/jupyterlab/pull/11536) ([@dependabot](https://github.com/dependabot)) +- Bump tmpl from 1.0.4 to 1.0.5 [#11512](https://github.com/jupyterlab/jupyterlab/pull/11512) ([@dependabot](https://github.com/dependabot)) +- Bump semver-regex from 3.1.2 to 3.1.3 [#11511](https://github.com/jupyterlab/jupyterlab/pull/11511) ([@dependabot](https://github.com/dependabot)) +- Update `sanitize-html` pin to `3.5.3` [#11510](https://github.com/jupyterlab/jupyterlab/pull/11510) ([@krassowski](https://github.com/krassowski)) +- Increase notebook markdown test robustness [#11507](https://github.com/jupyterlab/jupyterlab/pull/11507) ([@fcollonval](https://github.com/fcollonval)) +- Enforce labels on PRs [#11496](https://github.com/jupyterlab/jupyterlab/pull/11496) ([@blink1073](https://github.com/blink1073)) +- Update release instructions and add video [#11487](https://github.com/jupyterlab/jupyterlab/pull/11487) ([@blink1073](https://github.com/blink1073)) +- Reduce flake on non-LaTeX highlighting test [#11470](https://github.com/jupyterlab/jupyterlab/pull/11470) ([@krassowski](https://github.com/krassowski)) +- Merge duplicated namespace [#11461](https://github.com/jupyterlab/jupyterlab/pull/11461) ([@fcollonval](https://github.com/fcollonval)) +- Close answered issues more quickly if there are no updates. [#11446](https://github.com/jupyterlab/jupyterlab/pull/11446) ([@jasongrout](https://github.com/jasongrout)) +- Use the root yarn.lock in staging when making a release. [#11433](https://github.com/jupyterlab/jupyterlab/pull/11433) ([@jasongrout](https://github.com/jasongrout)) +- Enforce ascii-only identifiers [#11432](https://github.com/jupyterlab/jupyterlab/pull/11432) ([@jasongrout](https://github.com/jasongrout)) +- Update Lumino to latest versions [#11425](https://github.com/jupyterlab/jupyterlab/pull/11425) ([@jasongrout](https://github.com/jasongrout)) + +- Document notebook DOM structure [#11609](https://github.com/jupyterlab/jupyterlab/pull/11609) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Update Affiliations [#11596](https://github.com/jupyterlab/jupyterlab/pull/11596) ([@blink1073](https://github.com/blink1073)) +- Missing parenthesis [#11590](https://github.com/jupyterlab/jupyterlab/pull/11590) ([@davidbrochart](https://github.com/davidbrochart)) +- Fix some keywords in typedoc [#11542](https://github.com/jupyterlab/jupyterlab/pull/11542) ([@fcollonval](https://github.com/fcollonval)) +- Clean up Frontend Typings [#11537](https://github.com/jupyterlab/jupyterlab/pull/11537) ([@jtpio](https://github.com/jtpio)) +- Fix docstring for cell footer [#11503](https://github.com/jupyterlab/jupyterlab/pull/11503) ([@martinRenou](https://github.com/martinRenou)) +- Update screenshots and text for user interface docs [#11499](https://github.com/jupyterlab/jupyterlab/pull/11499) ([@krassowski](https://github.com/krassowski)) +- Update release instructions and add video [#11487](https://github.com/jupyterlab/jupyterlab/pull/11487) ([@blink1073](https://github.com/blink1073)) +- Update the release documentation to recommend using the Jupyter Releaser [#11440](https://github.com/jupyterlab/jupyterlab/pull/11440) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Creates a new accordion panel with toolbar in the ui-components package [#11369](https://github.com/jupyterlab/jupyterlab/pull/11369) ([@hbcarlos](https://github.com/hbcarlos)) +- Toc running cell indicator [#11356](https://github.com/jupyterlab/jupyterlab/pull/11356) ([@andrewfulton9](https://github.com/andrewfulton9)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-11-09&to=2021-12-07&type=c)) + +[@0x2b3bfa0](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A0x2b3bfa0+updated%3A2021-11-09..2021-12-07&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-11-09..2021-12-07&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-11-09..2021-12-07&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-11-09..2021-12-07&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-11-09..2021-12-07&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2021-11-09..2021-12-07&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-11-09..2021-12-07&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-11-09..2021-12-07&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-11-09..2021-12-07&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-11-09..2021-12-07&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-11-09..2021-12-07&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-11-09..2021-12-07&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-11-09..2021-12-07&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2021-11-09..2021-12-07&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-11-09..2021-12-07&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-11-09..2021-12-07&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2021-11-09..2021-12-07&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-11-09..2021-12-07&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-11-09..2021-12-07&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2021-11-09..2021-12-07&type=Issues) | [@skyetim](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Askyetim+updated%3A2021-11-09..2021-12-07&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-11-09..2021-12-07&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-11-09..2021-12-07&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-11-09..2021-12-07&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2021-11-09..2021-12-07&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-11-09..2021-12-07&type=Issues) + +## 4.0.0a15 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a14...1d7533f0f67cb9e32307ff6b9347a8e814bb55d7)) + +### Enhancements made + +- Remove `Blueprint` [#11173](https://github.com/jupyterlab/jupyterlab/pull/11173) ([@fcollonval](https://github.com/fcollonval)) +- Add execution progress indicator [#10730](https://github.com/jupyterlab/jupyterlab/pull/10730) ([@trungleduc](https://github.com/trungleduc)) + +### Bugs fixed + +- Bump Yjs dependencies and fix modeldb overwriting yjs content [#11398](https://github.com/jupyterlab/jupyterlab/pull/11398) ([@dmonad](https://github.com/dmonad)) +- Make `orig_nbformat` optional #11005 [#11370](https://github.com/jupyterlab/jupyterlab/pull/11370) ([@nanoant](https://github.com/nanoant)) +- Fix Handling of WebSocket Startup Errors [#11358](https://github.com/jupyterlab/jupyterlab/pull/11358) ([@blink1073](https://github.com/blink1073)) +- Only trigger dirty status update on value changes [#11346](https://github.com/jupyterlab/jupyterlab/pull/11346) ([@krassowski](https://github.com/krassowski)) +- Updated dialog with text to a reasonable width [#11331](https://github.com/jupyterlab/jupyterlab/pull/11331) ([@3coins](https://github.com/3coins)) +- Fix for terminal theme style [#11291](https://github.com/jupyterlab/jupyterlab/pull/11291) ([@3coins](https://github.com/3coins)) + +### Maintenance and upkeep improvements + +- Makes `ILabShell` optional in `toc` extension [#11420](https://github.com/jupyterlab/jupyterlab/pull/11420) ([@jweill-aws](https://github.com/jweill-aws)) +- Add `jupyterlab` prefix to the `Galata` artifacts [#11405](https://github.com/jupyterlab/jupyterlab/pull/11405) ([@jtpio](https://github.com/jtpio)) +- Fix rebuilding JLab in benchmark CI [#11399](https://github.com/jupyterlab/jupyterlab/pull/11399) ([@fcollonval](https://github.com/fcollonval)) +- Modify dump of `webpack` config to include `RegEx` expressions [#11397](https://github.com/jupyterlab/jupyterlab/pull/11397) ([@rfox12](https://github.com/rfox12)) +- 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)) +- Fix comment on PR action [#11354](https://github.com/jupyterlab/jupyterlab/pull/11354) ([@fcollonval](https://github.com/fcollonval)) +- Relax `@playright/test` dependency in Galata [#11112](https://github.com/jupyterlab/jupyterlab/pull/11112) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Improve documentation on galata setup [#11391](https://github.com/jupyterlab/jupyterlab/pull/11391) ([@fcollonval](https://github.com/fcollonval)) +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Recommend providing screenshots for translators [#11357](https://github.com/jupyterlab/jupyterlab/pull/11357) ([@krassowski](https://github.com/krassowski)) +- Fix outdated `clearSignalData` reference (now `Signal.clearData`) [#11339](https://github.com/jupyterlab/jupyterlab/pull/11339) ([@krassowski](https://github.com/krassowski)) +- Remove `Blueprint` [#11173](https://github.com/jupyterlab/jupyterlab/pull/11173) ([@fcollonval](https://github.com/fcollonval)) +- Adds recommendation to install `Prettier` extension [#11363](https://github.com/jupyterlab/jupyterlab/pull/11363) ([@jweill-aws](https://github.com/jweill-aws)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-20&to=2021-11-09&type=c)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-10-20..2021-11-09&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-20..2021-11-09&type=Issues) | [@ceesu](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aceesu+updated%3A2021-10-20..2021-11-09&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-10-20..2021-11-09&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-10-20..2021-11-09&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-10-20..2021-11-09&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-10-20..2021-11-09&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-20..2021-11-09&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-10-20..2021-11-09&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-10-20..2021-11-09&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-10-20..2021-11-09&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-20..2021-11-09&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2021-10-20..2021-11-09&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-10-20..2021-11-09&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-10-20..2021-11-09&type=Issues) | [@nanoant](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ananoant+updated%3A2021-10-20..2021-11-09&type=Issues) | [@rfox12](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arfox12+updated%3A2021-10-20..2021-11-09&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-10-20..2021-11-09&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-10-20..2021-11-09&type=Issues) | [@williamstein](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awilliamstein+updated%3A2021-10-20..2021-11-09&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2021-10-20..2021-11-09&type=Issues) + +## 4.0.0a14 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a13...8c67f5949af19503e447a83584885f919e115c47)) + +### Enhancements made + +- Added button theme variables, updated button style [#11264](https://github.com/jupyterlab/jupyterlab/pull/11264) ([@3coins](https://github.com/3coins)) + +### Bugs fixed + +- Fix for debugger not working for scripts [#11311](https://github.com/jupyterlab/jupyterlab/pull/11311) ([@3coins](https://github.com/3coins)) +- Added handling of '\r' ended files [#11310](https://github.com/jupyterlab/jupyterlab/pull/11310) ([@lucabarcelos](https://github.com/lucabarcelos)) +- 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)) +- Normalize cell source \r line endings [#11271](https://github.com/jupyterlab/jupyterlab/pull/11271) ([@jasongrout](https://github.com/jasongrout)) + +### Maintenance and upkeep improvements + +- Pass version spec as an input [#11322](https://github.com/jupyterlab/jupyterlab/pull/11322) ([@jtpio](https://github.com/jtpio)) +- Added debugger UI tests for scripts [#11319](https://github.com/jupyterlab/jupyterlab/pull/11319) ([@3coins](https://github.com/3coins)) +- Update the latest `@lumino` packages [#11281](https://github.com/jupyterlab/jupyterlab/pull/11281) ([@jtpio](https://github.com/jtpio)) +- Extension upgrade script: Avoid throwing exceptions for certain package.json files [#11278](https://github.com/jupyterlab/jupyterlab/pull/11278) ([@ammgws](https://github.com/ammgws)) +- UI tests for debugger [#11250](https://github.com/jupyterlab/jupyterlab/pull/11250) ([@3coins](https://github.com/3coins)) +- Run comparative benchmark [#11128](https://github.com/jupyterlab/jupyterlab/pull/11128) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Add note on weekly dev notes [#11317](https://github.com/jupyterlab/jupyterlab/pull/11317) ([@fcollonval](https://github.com/fcollonval)) +- amend changelog - follow up issue 11304 [#11309](https://github.com/jupyterlab/jupyterlab/pull/11309) ([@achimgaedke](https://github.com/achimgaedke)) +- update the binder sha to the latest demo version [#11302](https://github.com/jupyterlab/jupyterlab/pull/11302) ([@akhmerov](https://github.com/akhmerov)) +- Add note on the server parameter for hidden files. [#11293](https://github.com/jupyterlab/jupyterlab/pull/11293) ([@fcollonval](https://github.com/fcollonval)) +- Clarify sidebar switching settings [#11270](https://github.com/jupyterlab/jupyterlab/pull/11270) ([@joelostblom](https://github.com/joelostblom)) +- Add missing changelog entry from 4.0.0a13 [#11268](https://github.com/jupyterlab/jupyterlab/pull/11268) ([@blink1073](https://github.com/blink1073)) +- Run comparative benchmark [#11128](https://github.com/jupyterlab/jupyterlab/pull/11128) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-08&to=2021-10-20&type=c)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-10-08..2021-10-20&type=Issues) | [@achimgaedke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aachimgaedke+updated%3A2021-10-08..2021-10-20&type=Issues) | [@akhmerov](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aakhmerov+updated%3A2021-10-08..2021-10-20&type=Issues) | [@ammgws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aammgws+updated%3A2021-10-08..2021-10-20&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-08..2021-10-20&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-10-08..2021-10-20&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-10-08..2021-10-20&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-08..2021-10-20&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-10-08..2021-10-20&type=Issues) | [@joelostblom](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajoelostblom+updated%3A2021-10-08..2021-10-20&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-10-08..2021-10-20&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-08..2021-10-20&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-10-08..2021-10-20&type=Issues) | [@lucabarcelos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Alucabarcelos+updated%3A2021-10-08..2021-10-20&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-10-08..2021-10-20&type=Issues) + +## 4.0.0a13 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a12...e35f100082cbfed37eeca587d1b87ae79ef418ee)) + +### Bugs fixed + +- Fix Webpack crypto handling [#11249](https://github.com/jupyterlab/jupyterlab/pull/11249) ([@blink1073](https://github.com/blink1073)) + +### Maintenance and upkeep improvements + +- Add documentation label to markdown files [#11262](https://github.com/jupyterlab/jupyterlab/pull/11262) ([@blink1073](https://github.com/blink1073)) +- Fix nbconvert compatibility with fips-enabled openssl [#11261](https://github.com/jupyterlab/jupyterlab/pull/11261) ([@blink1073](https://github.com/blink1073)) + +### Documentation improvements + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-10-06&to=2021-10-08&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-10-06..2021-10-08&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-10-06..2021-10-08&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-10-06..2021-10-08&type=Issues) + +## 4.0.0a12 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a11...cb507227fa1673c2e7d787873f639d0ac13c2023)) + +### Enhancements made + +- Enable document wide history tracking [#10949](https://github.com/jupyterlab/jupyterlab/pull/10949) ([@echarles](https://github.com/echarles)) +- Make check margin between last modified timestamps on disk and client configurable [#11153](https://github.com/jupyterlab/jupyterlab/pull/11153) ([@ph-ph](https://github.com/ph-ph)) +- Add a menu entry to show/hide hidden files in the filebrowser [#10769](https://github.com/jupyterlab/jupyterlab/pull/10769) ([@loichuder](https://github.com/loichuder)) +- Add option to choose checkpoint [#9670](https://github.com/jupyterlab/jupyterlab/pull/9670) ([@hMED22](https://github.com/hMED22)) + +### Bugs fixed + +- Use standard hash type in webpack build [#11234](https://github.com/jupyterlab/jupyterlab/pull/11234) ([@blink1073](https://github.com/blink1073)) +- Remove format from fetching options if null [#11229](https://github.com/jupyterlab/jupyterlab/pull/11229) ([@loichuder](https://github.com/loichuder)) +- don't 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)) +- Fix renaming issue in collaborative mode [#11197](https://github.com/jupyterlab/jupyterlab/pull/11197) ([@dmonad](https://github.com/dmonad)) +- Restore workspace and open _tree_ path [#11168](https://github.com/jupyterlab/jupyterlab/pull/11168) ([@fcollonval](https://github.com/fcollonval)) +- Share notebook's metadata [#11064](https://github.com/jupyterlab/jupyterlab/pull/11064) ([@hbcarlos](https://github.com/hbcarlos)) + +### Maintenance and upkeep improvements + +- Run Linter [#11238](https://github.com/jupyterlab/jupyterlab/pull/11238) ([@blink1073](https://github.com/blink1073)) +- Fix Release Check [#11218](https://github.com/jupyterlab/jupyterlab/pull/11218) ([@fcollonval](https://github.com/fcollonval)) +- Check i18n will pass on zeroed patch pre-release version [#11214](https://github.com/jupyterlab/jupyterlab/pull/11214) ([@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)) +- refactor window.open to make it work also in desktop app [#11202](https://github.com/jupyterlab/jupyterlab/pull/11202) ([@mbektas](https://github.com/mbektas)) +- Rename "JupyterLab Theme" to "Theme" [#11198](https://github.com/jupyterlab/jupyterlab/pull/11198) ([@jtpio](https://github.com/jtpio)) +- Use only context and id to check i18n [#11190](https://github.com/jupyterlab/jupyterlab/pull/11190) ([@fcollonval](https://github.com/fcollonval)) +- Update webpack dependencies [#11184](https://github.com/jupyterlab/jupyterlab/pull/11184) ([@jtpio](https://github.com/jtpio)) +- Correct galata repository urls [#11181](https://github.com/jupyterlab/jupyterlab/pull/11181) ([@fcollonval](https://github.com/fcollonval)) +- Fix kernelspec logo handling [#11175](https://github.com/jupyterlab/jupyterlab/pull/11175) ([@jtpio](https://github.com/jtpio)) +- Remove unused command id in the translation extension [#11164](https://github.com/jupyterlab/jupyterlab/pull/11164) ([@jtpio](https://github.com/jtpio)) +- Resolve typing errors in kernel mocks [#11159](https://github.com/jupyterlab/jupyterlab/pull/11159) ([@ph-ph](https://github.com/ph-ph)) + +### Documentation improvements + +### Other merged PRs + +- Forwardport changelog entries [#11240](https://github.com/jupyterlab/jupyterlab/pull/11240) ([@blink1073](https://github.com/blink1073)) +- Use disableDocumentWideUndoRedo instead of enableDocumentWideUndoRedo [#11215](https://github.com/jupyterlab/jupyterlab/pull/11215) ([@echarles](https://github.com/echarles)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-27&to=2021-10-06&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-27..2021-10-06&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-09-27..2021-10-06&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-27..2021-10-06&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-09-27..2021-10-06&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-27..2021-10-06&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-27..2021-10-06&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-09-27..2021-10-06&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-27..2021-10-06&type=Issues) | [@hMED22](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AhMED22+updated%3A2021-09-27..2021-10-06&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-09-27..2021-10-06&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-27..2021-10-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-27..2021-10-06&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-27..2021-10-06&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-27..2021-10-06&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-27..2021-10-06&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-09-27..2021-10-06&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-09-27..2021-10-06&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-09-27..2021-10-06&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-27..2021-10-06&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aminrk+updated%3A2021-09-27..2021-10-06&type=Issues) | [@ph-ph](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aph-ph+updated%3A2021-09-27..2021-10-06&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-09-27..2021-10-06&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-27..2021-10-06&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-09-27..2021-10-06&type=Issues) + +## 4.0.0a11 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a10...c6b14b6efc96043fb4e6af8cec5914a68d8db113)) + +### Enhancements made + +- reuse cell id of cut cell on cut + paste [#11138](https://github.com/jupyterlab/jupyterlab/pull/11138) ([@smacke](https://github.com/smacke)) +- Add ability to hide the header bar in simple mode [#11107](https://github.com/jupyterlab/jupyterlab/pull/11107) ([@fcollonval](https://github.com/fcollonval)) +- Fetch translations via the `ServerConnection.ISettings` [#11091](https://github.com/jupyterlab/jupyterlab/pull/11091) ([@jtpio](https://github.com/jtpio)) +- Add Side-by-side Rendering [#10648](https://github.com/jupyterlab/jupyterlab/pull/10648) ([@jess-x](https://github.com/jess-x)) + +### Bugs fixed + +- Normalize notebook cell line endings to \n [#11141](https://github.com/jupyterlab/jupyterlab/pull/11141) ([@jasongrout](https://github.com/jasongrout)) +- Fix auto close brackets for console [#11137](https://github.com/jupyterlab/jupyterlab/pull/11137) ([@ohrely](https://github.com/ohrely)) +- Improve the reactive toolbar [#11108](https://github.com/jupyterlab/jupyterlab/pull/11108) ([@fcollonval](https://github.com/fcollonval)) +- use posix explicitly for PathExt [#11099](https://github.com/jupyterlab/jupyterlab/pull/11099) ([@mbektas](https://github.com/mbektas)) +- Update the lock after every request [#11092](https://github.com/jupyterlab/jupyterlab/pull/11092) ([@hbcarlos](https://github.com/hbcarlos)) + +### Maintenance and upkeep improvements + +- Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) +- Refactor `BenchmarkReporter` [#11090](https://github.com/jupyterlab/jupyterlab/pull/11090) ([@trungleduc](https://github.com/trungleduc)) + +### Documentation improvements + +- fix up #11117 - typo in docs: page_config.json [#11152](https://github.com/jupyterlab/jupyterlab/pull/11152) ([@achimgaedke](https://github.com/achimgaedke)) +- Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) +- Remove item from changelog that slips through [#11110](https://github.com/jupyterlab/jupyterlab/pull/11110) ([@fcollonval](https://github.com/fcollonval)) +- Add a note on the Jupyter Releaser in the extension tutorial [#11085](https://github.com/jupyterlab/jupyterlab/pull/11085) ([@jtpio](https://github.com/jtpio)) +- Simplify installation instructions in README [#10559](https://github.com/jupyterlab/jupyterlab/pull/10559) ([@chrisyeh96](https://github.com/chrisyeh96)) + +### Other merged PRs + +- Bump nth-check from 2.0.0 to 2.0.1 in /jupyterlab/staging [#11109](https://github.com/jupyterlab/jupyterlab/pull/11109) ([@dependabot](https://github.com/dependabot)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-15&to=2021-09-27&type=c)) + +[@achimgaedke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aachimgaedke+updated%3A2021-09-15..2021-09-27&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-15..2021-09-27&type=Issues) | [@chrisyeh96](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Achrisyeh96+updated%3A2021-09-15..2021-09-27&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adependabot+updated%3A2021-09-15..2021-09-27&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-15..2021-09-27&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-15..2021-09-27&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-15..2021-09-27&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-09-15..2021-09-27&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-15..2021-09-27&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-15..2021-09-27&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-09-15..2021-09-27&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-15..2021-09-27&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-15..2021-09-27&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-15..2021-09-27&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-15..2021-09-27&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-09-15..2021-09-27&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-09-15..2021-09-27&type=Issues) | [@ohrely](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aohrely+updated%3A2021-09-15..2021-09-27&type=Issues) | [@smacke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asmacke+updated%3A2021-09-15..2021-09-27&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-09-15..2021-09-27&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-15..2021-09-27&type=Issues) + +## 4.0.0a10 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a9...52f961be656da60e2a39ef502de7991ee0436e26)) + +### Enhancements made + +- Remove retry part from test folder name [#11070](https://github.com/jupyterlab/jupyterlab/pull/11070) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Indent comments (#6957) [#11063](https://github.com/jupyterlab/jupyterlab/pull/11063) ([@josephrocca](https://github.com/josephrocca)) +- Retain the rtc lock until the user releases it [#11026](https://github.com/jupyterlab/jupyterlab/pull/11026) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix user preferences not being considered for Text Editor [#10868](https://github.com/jupyterlab/jupyterlab/pull/10868) ([@Mithil467](https://github.com/Mithil467)) +- Improve resizing behavior of debugger panels [#10653](https://github.com/jupyterlab/jupyterlab/pull/10653) ([@trungleduc](https://github.com/trungleduc)) + +### Maintenance and upkeep improvements + +- Skip flaky debugger test [#11083](https://github.com/jupyterlab/jupyterlab/pull/11083) ([@fcollonval](https://github.com/fcollonval)) +- Fix/duplicate-statement [#11082](https://github.com/jupyterlab/jupyterlab/pull/11082) ([@fcollonval](https://github.com/fcollonval)) +- Revert "Constrain ipykernel version on CI" [#11076](https://github.com/jupyterlab/jupyterlab/pull/11076) ([@jtpio](https://github.com/jtpio)) +- Check changes on translatable strings [#11036](https://github.com/jupyterlab/jupyterlab/pull/11036) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Split settings schema for inclusion in documentation [#11067](https://github.com/jupyterlab/jupyterlab/pull/11067) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-13&to=2021-09-15&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-13..2021-09-15&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-13..2021-09-15&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-13..2021-09-15&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-13..2021-09-15&type=Issues) | [@josephrocca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajosephrocca+updated%3A2021-09-13..2021-09-15&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-13..2021-09-15&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-13..2021-09-15&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-13..2021-09-15&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-13..2021-09-15&type=Issues) | [@Mithil467](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AMithil467+updated%3A2021-09-13..2021-09-15&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-09-13..2021-09-15&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-13..2021-09-15&type=Issues) + +## 4.0.0a9 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a8...d103ccc3d16db524bed90fb1eebb6ce7616e224f)) + +### Enhancements made + +- update inspector label [#11049](https://github.com/jupyterlab/jupyterlab/pull/11049) ([@legendb317](https://github.com/legendb317)) + +### Bugs fixed + +- Use posix paths explicitly [#11031](https://github.com/jupyterlab/jupyterlab/pull/11031) ([@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 + +- Clean up bumpversion [#11056](https://github.com/jupyterlab/jupyterlab/pull/11056) ([@blink1073](https://github.com/blink1073)) +- Use `details` block in benchmark report [#11054](https://github.com/jupyterlab/jupyterlab/pull/11054) ([@fcollonval](https://github.com/fcollonval)) +- Constrain ipykernel version on CI [#11052](https://github.com/jupyterlab/jupyterlab/pull/11052) ([@fcollonval](https://github.com/fcollonval)) +- Fix benchmark PR commenting for forks [#11047](https://github.com/jupyterlab/jupyterlab/pull/11047) ([@fcollonval](https://github.com/fcollonval)) +- Fix prettier error [#11043](https://github.com/jupyterlab/jupyterlab/pull/11043) ([@fcollonval](https://github.com/fcollonval)) +- Use JupyterLab Probot for Binder Links [#11039](https://github.com/jupyterlab/jupyterlab/pull/11039) ([@blink1073](https://github.com/blink1073)) +- Make debugger jest test more robust [#11032](https://github.com/jupyterlab/jupyterlab/pull/11032) ([@fcollonval](https://github.com/fcollonval)) +- Add benchmark tests [#10936](https://github.com/jupyterlab/jupyterlab/pull/10936) ([@fcollonval](https://github.com/fcollonval)) + +### API and Breaking Changes + +- Add benchmark tests [#10936](https://github.com/jupyterlab/jupyterlab/pull/10936) ([@fcollonval](https://github.com/fcollonval)) + +### Other merged PRs + +- Remove status bar item flickering [#11065](https://github.com/jupyterlab/jupyterlab/pull/11065) ([@fcollonval](https://github.com/fcollonval)) +- use path.posix explicitly for URLs [#11048](https://github.com/jupyterlab/jupyterlab/pull/11048) ([@mbektas](https://github.com/mbektas)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-08&to=2021-09-13&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-08..2021-09-13&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-08..2021-09-13&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-08..2021-09-13&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-08..2021-09-13&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-08..2021-09-13&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-08..2021-09-13&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-08..2021-09-13&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-08..2021-09-13&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-08..2021-09-13&type=Issues) | [@legendb317](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Alegendb317+updated%3A2021-09-08..2021-09-13&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-09-08..2021-09-13&type=Issues) | [@Mithil467](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AMithil467+updated%3A2021-09-08..2021-09-13&type=Issues) + +## 4.0.0a8 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a7...094056ad2d728327dbeef26aabeee29ece584487)) + +### Bugs fixed + +- use correct nbformat version - fixes #11005 [#11017](https://github.com/jupyterlab/jupyterlab/pull/11017) ([@dmonad](https://github.com/dmonad)) +- Restore Copy shareable link use of shareUrl [#11011](https://github.com/jupyterlab/jupyterlab/pull/11011) ([@fcollonval](https://github.com/fcollonval)) +- Fix ignored promise leading to incorrect initial tooltip position [#11010](https://github.com/jupyterlab/jupyterlab/pull/11010) ([@krassowski](https://github.com/krassowski)) +- Add a guard to avoid kernel deadlock on multiple input request [#10792](https://github.com/jupyterlab/jupyterlab/pull/10792) ([@echarles](https://github.com/echarles)) +- Translate factory names by adding `label` [#11006](https://github.com/jupyterlab/jupyterlab/pull/11006) ([@krassowski](https://github.com/krassowski)) +- fix #10997 - increase max_message_size of websocket messages [#11003](https://github.com/jupyterlab/jupyterlab/pull/11003) ([@dmonad](https://github.com/dmonad)) +- Fix typo in nbformat dialog [#11001](https://github.com/jupyterlab/jupyterlab/pull/11001) ([@davidbrochart](https://github.com/davidbrochart)) +- Fix missing translation wrappers in the debugger [#10989](https://github.com/jupyterlab/jupyterlab/pull/10989) ([@krassowski](https://github.com/krassowski)) + +### Maintenance and upkeep improvements + +- Cache ESLint Data [#11025](https://github.com/jupyterlab/jupyterlab/pull/11025) ([@blink1073](https://github.com/blink1073)) +- Clean up notebook test utils [#11021](https://github.com/jupyterlab/jupyterlab/pull/11021) ([@fcollonval](https://github.com/fcollonval)) +- Make Test Server Configurable [#11015](https://github.com/jupyterlab/jupyterlab/pull/11015) ([@fcollonval](https://github.com/fcollonval)) +- 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)) +- Move RankedMenu test to ui-components [#10992](https://github.com/jupyterlab/jupyterlab/pull/10992) ([@fcollonval](https://github.com/fcollonval)) +- Fix link to Playwright fixtures in the galata README [#10988](https://github.com/jupyterlab/jupyterlab/pull/10988) ([@jtpio](https://github.com/jtpio)) +- Change "Export Notebook As" to "Save and Export Notebook As" [#10904](https://github.com/jupyterlab/jupyterlab/pull/10904) ([@bsyouness](https://github.com/bsyouness)) + +### Documentation improvements + +- Update documentation for internationalization [#11024](https://github.com/jupyterlab/jupyterlab/pull/11024) ([@fcollonval](https://github.com/fcollonval)) +- Configure sphinx for gettext [#11022](https://github.com/jupyterlab/jupyterlab/pull/11022) ([@fcollonval](https://github.com/fcollonval)) + +### 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) | [@bsyouness](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Absyouness+updated%3A2021-09-01..2021-09-08&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-09-01..2021-09-08&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+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) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+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) + +## 4.0.0a7 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a6...0350c6e6cafa06e0a4903507524789d938b75710)) + +### Enhancements made + +- Add editable selector [#10957](https://github.com/jupyterlab/jupyterlab/pull/10957) ([@krassowska](https://github.com/krassowska)) +- Removed debug switch, added bug button state update [#10727](https://github.com/jupyterlab/jupyterlab/pull/10727) ([@3coins](https://github.com/3coins)) +- Add debugger variable renderer based on mime type [#10299](https://github.com/jupyterlab/jupyterlab/pull/10299) ([@fcollonval](https://github.com/fcollonval)) + +### Bugs fixed + +- Remove the non-null assertion on `IDebugger.ISources` [#10976](https://github.com/jupyterlab/jupyterlab/pull/10976) ([@fcollonval](https://github.com/fcollonval)) +- Protect against undefined delegated label [#10972](https://github.com/jupyterlab/jupyterlab/pull/10972) ([@fcollonval](https://github.com/fcollonval)) +- ForwardPort PR #10898 on master: Render placeholder at correct index [#10959](https://github.com/jupyterlab/jupyterlab/pull/10959) ([@echarles](https://github.com/echarles)) +- Fix lack of translation of part of "Saving completed" and friends [#10958](https://github.com/jupyterlab/jupyterlab/pull/10958) ([@krassowski](https://github.com/krassowski)) +- Fix browser tab name [#10952](https://github.com/jupyterlab/jupyterlab/pull/10952) ([@tejasmorkar](https://github.com/tejasmorkar)) +- Simplify IRankedMenu interface [#10943](https://github.com/jupyterlab/jupyterlab/pull/10943) ([@fcollonval](https://github.com/fcollonval)) +- Add "menu" context for translation of menu labels [#10932](https://github.com/jupyterlab/jupyterlab/pull/10932) ([@krassowski](https://github.com/krassowski)) +- Add undoManager to inserted cells [#10899](https://github.com/jupyterlab/jupyterlab/pull/10899) ([@hbcarlos](https://github.com/hbcarlos)) + +### Maintenance and upkeep improvements + +- Update to lerna 4 [#10983](https://github.com/jupyterlab/jupyterlab/pull/10983) ([@jtpio](https://github.com/jtpio)) +- Galata: Update reference screenshots [#10982](https://github.com/jupyterlab/jupyterlab/pull/10982) ([@jtpio](https://github.com/jtpio)) +- Improve Galata documentation and setup [#10980](https://github.com/jupyterlab/jupyterlab/pull/10980) ([@fcollonval](https://github.com/fcollonval)) +- 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)) +- Chore: fix typo in comments [#10953](https://github.com/jupyterlab/jupyterlab/pull/10953) ([@agoose77](https://github.com/agoose77)) +- Bump major Galata version [#10951](https://github.com/jupyterlab/jupyterlab/pull/10951) ([@fcollonval](https://github.com/fcollonval)) +- More robust UI tests [#10950](https://github.com/jupyterlab/jupyterlab/pull/10950) ([@fcollonval](https://github.com/fcollonval)) +- More Publish Integrity [#10937](https://github.com/jupyterlab/jupyterlab/pull/10937) ([@afshin](https://github.com/afshin)) +- Add Galata in JupyterLab [#10796](https://github.com/jupyterlab/jupyterlab/pull/10796) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Improve Galata documentation and setup [#10980](https://github.com/jupyterlab/jupyterlab/pull/10980) ([@fcollonval](https://github.com/fcollonval)) +- Add process for adding a language [#10961](https://github.com/jupyterlab/jupyterlab/pull/10961) ([@fcollonval](https://github.com/fcollonval)) +- Improve release notes for 3.1 [#10954](https://github.com/jupyterlab/jupyterlab/pull/10954) ([@krassowski](https://github.com/krassowski)) +- Fix formatting of a link in the changelog [#10945](https://github.com/jupyterlab/jupyterlab/pull/10945) ([@jtpio](https://github.com/jtpio)) + +### API and Breaking Changes + +- Add debugger variable renderer based on mime type [#10299](https://github.com/jupyterlab/jupyterlab/pull/10299) ([@fcollonval](https://github.com/fcollonval)) + +### 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)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-08-25..2021-09-01&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-25..2021-09-01&type=Issues) | [@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) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+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) | [@krassowska](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowska+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) | [@tejasmorkar](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atejasmorkar+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) + +## 4.0.0a6 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a5...8a727b71bde05944214a2c53fe1f7e6e33864701)) + +### 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 + +- Correct the documentation for packaging [#10910](https://github.com/jupyterlab/jupyterlab/pull/10910) ([@fcollonval](https://github.com/fcollonval)) +- Forward port 3.1.8 Changelog Entry [#10907](https://github.com/jupyterlab/jupyterlab/pull/10907) ([@blink1073](https://github.com/blink1073)) +- Add internationalization documentation [#10893](https://github.com/jupyterlab/jupyterlab/pull/10893) ([@fcollonval](https://github.com/fcollonval)) + +### 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)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-24..2021-08-25&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-24..2021-08-25&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+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) | [@Mithil467](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AMithil467+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) + +## 4.0.0a5 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a4...0cf99e5d3e3881df8b406d097a46e91569a02f52)) + +### Bugs fixed + +- Improve language choice menu and dialog [#10885](https://github.com/jupyterlab/jupyterlab/pull/10885) ([@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)) +- Compose only the needed property when transforming the settings [#10880](https://github.com/jupyterlab/jupyterlab/pull/10880) ([@fcollonval](https://github.com/fcollonval)) +- 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)) +- Add translations for notebook mode name [#10865](https://github.com/jupyterlab/jupyterlab/pull/10865) ([@krassowski](https://github.com/krassowski)) +- Add missing link in passing translator down to kernel selector [#10864](https://github.com/jupyterlab/jupyterlab/pull/10864) ([@krassowski](https://github.com/krassowski)) +- Fix code names showing up in new translations, add docs [#10860](https://github.com/jupyterlab/jupyterlab/pull/10860) ([@krassowski](https://github.com/krassowski)) +- Added throttling for toolbar resize (#10826) [#10854](https://github.com/jupyterlab/jupyterlab/pull/10854) ([@3coins](https://github.com/3coins)) +- Shutdown sessions/terminals on shutdown [#10843](https://github.com/jupyterlab/jupyterlab/pull/10843) ([@martinRenou](https://github.com/martinRenou)) +- Get metadata from shared model when serializing the notebook to JSON [#10804](https://github.com/jupyterlab/jupyterlab/pull/10804) ([@hbcarlos](https://github.com/hbcarlos)) + +### Maintenance and upkeep improvements + +- Lint Cleanup [#10900](https://github.com/jupyterlab/jupyterlab/pull/10900) ([@blink1073](https://github.com/blink1073)) +- Publish Cleanup [#10891](https://github.com/jupyterlab/jupyterlab/pull/10891) ([@fcollonval](https://github.com/fcollonval)) +- Edit binder ref for demo [#10877](https://github.com/jupyterlab/jupyterlab/pull/10877) ([@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)) +- Set the `camelcase` ESLint rule to `warn` [#10500](https://github.com/jupyterlab/jupyterlab/pull/10500) ([@jtpio](https://github.com/jtpio)) + +### Other merged PRs + +- Forwardport 3.1.7 Changelog entry [#10845](https://github.com/jupyterlab/jupyterlab/pull/10845) ([@blink1073](https://github.com/blink1073)) + +### 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)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-08-16..2021-08-24&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-16..2021-08-24&type=Issues) | [@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) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-08-16..2021-08-24&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+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) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+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) + +## 4.0.0a4 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a3...26c35fef04a6b34564662965741f561701becf05)) + +### Enhancements made + +- Don't sort context menu items by selector [#10666](https://github.com/jupyterlab/jupyterlab/pull/10666) ([@fcollonval](https://github.com/fcollonval)) +- Add show trailing whitespace option to Notebook and Text Editor [#10632](https://github.com/jupyterlab/jupyterlab/pull/10632) ([@richardkang112](https://github.com/richardkang112)) +- Allow extensions and users to customize easily toolbar items. [#10469](https://github.com/jupyterlab/jupyterlab/pull/10469) ([@fcollonval](https://github.com/fcollonval)) +- Implemented Restart and debug [#10462](https://github.com/jupyterlab/jupyterlab/pull/10462) ([@JohanMabille](https://github.com/JohanMabille)) +- Add `isConnected` to `ServiceManager`, use it in `hub-extension` [#10156](https://github.com/jupyterlab/jupyterlab/pull/10156) ([@vkaidalov-rft](https://github.com/vkaidalov-rft)) + +### Bugs fixed + +- Fix link to the security documentation [#10836](https://github.com/jupyterlab/jupyterlab/pull/10836) ([@krassowski](https://github.com/krassowski)) +- Fix missing break in switch [#10829](https://github.com/jupyterlab/jupyterlab/pull/10829) ([@fcollonval](https://github.com/fcollonval)) +- The dirty indicator does not get cleared up after reverting changes [#10812](https://github.com/jupyterlab/jupyterlab/pull/10812) ([@fcollonval](https://github.com/fcollonval)) +- Removed toolbar scrollbar [#10790](https://github.com/jupyterlab/jupyterlab/pull/10790) ([@3coins](https://github.com/3coins)) + +### Maintenance and upkeep improvements + +- References are duplicated in tsconfig.test.json [#10830](https://github.com/jupyterlab/jupyterlab/pull/10830) ([@fcollonval](https://github.com/fcollonval)) +- Remove outdated `npm-cli-login` utility from buildutils [#10828](https://github.com/jupyterlab/jupyterlab/pull/10828) ([@krassowski](https://github.com/krassowski)) + +### Documentation improvements + +- Allow extensions and users to customize easily toolbar items. [#10469](https://github.com/jupyterlab/jupyterlab/pull/10469) ([@fcollonval](https://github.com/fcollonval)) +- Clean up changelog [#10825](https://github.com/jupyterlab/jupyterlab/pull/10825) ([@blink1073](https://github.com/blink1073)) + +### 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) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+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) | [@richardkang112](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arichardkang112+updated%3A2021-08-12..2021-08-16&type=Issues) | [@vkaidalov-rft](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avkaidalov-rft+updated%3A2021-08-12..2021-08-16&type=Issues) + +## 4.0.0a3 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a2...b5a5937b0e6ab99eeeaedf80e6e1508e17629ad3)) + +### Bugs fixed + +- Use nullish operator instead of OR [#10811](https://github.com/jupyterlab/jupyterlab/pull/10811) ([@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)) + +### Maintenance and upkeep improvements + +- More Releaser Fixes [#10817](https://github.com/jupyterlab/jupyterlab/pull/10817) ([@afshin](https://github.com/afshin)) +- Comment invalid classifiers [#10815](https://github.com/jupyterlab/jupyterlab/pull/10815) ([@fcollonval](https://github.com/fcollonval)) + +### Documentation improvements + +- Fix documentation snippets [#10813](https://github.com/jupyterlab/jupyterlab/pull/10813) ([@fcollonval](https://github.com/fcollonval)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-11&to=2021-08-12&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-11..2021-08-12&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-11..2021-08-12&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-08-11..2021-08-12&type=Issues) | [@franckchen](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afranckchen+updated%3A2021-08-11..2021-08-12&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-11..2021-08-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-08-11..2021-08-12&type=Issues) + +## 4.0.0a2 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a1...132f74afab92fb6ca063644951464811d8ae87ae)) + +**_NOTE_** The Python Package for this release was not published due to our trove classifiers not yet being [available](https://github.com/jupyterlab/jupyterlab/issues/9538#issuecomment-897073510). + +### Bugs fixed + +- 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)) +- Revert input guard [#10779](https://github.com/jupyterlab/jupyterlab/pull/10779) ([@echarles](https://github.com/echarles)) + +### Maintenance and upkeep improvements + +- Clean up Link Caching Again [#10794](https://github.com/jupyterlab/jupyterlab/pull/10794) ([@afshin](https://github.com/afshin)) +- Clean up version integrity handling [#10787](https://github.com/jupyterlab/jupyterlab/pull/10787) ([@blink1073](https://github.com/blink1073)) +- Clean Up Major Version Bump Handling [#10766](https://github.com/jupyterlab/jupyterlab/pull/10766) ([@blink1073](https://github.com/blink1073)) + +### Documentation improvements + +- Add common-lisp-jupyter kernel to debugger list [#10786](https://github.com/jupyterlab/jupyterlab/pull/10786) ([@yitzchak](https://github.com/yitzchak)) +- add trove classifer docs, usage [#10731](https://github.com/jupyterlab/jupyterlab/pull/10731) ([@bollwyvl](https://github.com/bollwyvl)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-08-06&to=2021-08-11&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-08-06..2021-08-11&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-08-06..2021-08-11&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-08-06..2021-08-11&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-08-06..2021-08-11&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-08-06..2021-08-11&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-08-06..2021-08-11&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-08-06..2021-08-11&type=Issues) | [@yitzchak](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayitzchak+updated%3A2021-08-06..2021-08-11&type=Issues) + +## 4.0.0a1 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v4.0.0a0...cb406d3ee55eedd2f0df238958b37a4473cece02)) + +### Enhancements made + +- Responsive document toolbar [#10720](https://github.com/jupyterlab/jupyterlab/pull/10720) ([@3coins](https://github.com/3coins)) +- PR: Add preferred-dir handling [#10667](https://github.com/jupyterlab/jupyterlab/pull/10667) ([@goanpeca](https://github.com/goanpeca)) +- Toc: Run nested code cells directly from markdown headings [#10729](https://github.com/jupyterlab/jupyterlab/pull/10729) ([@jess-x](https://github.com/jess-x)) +- Normalize translation domain [#10728](https://github.com/jupyterlab/jupyterlab/pull/10728) ([@fcollonval](https://github.com/fcollonval)) +- RTC: persist rtc user color & name in state db [#10490](https://github.com/jupyterlab/jupyterlab/pull/10490) ([@jess-x](https://github.com/jess-x)) + +### 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)) +- Add translations for kernel statuses [#10738](https://github.com/jupyterlab/jupyterlab/pull/10738) ([@krassowski](https://github.com/krassowski)) +- Use appName in page title when restoring workspaces (vs master) [#10725](https://github.com/jupyterlab/jupyterlab/pull/10725) ([@bollwyvl](https://github.com/bollwyvl)) +- 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)) + +### Maintenance and upkeep improvements + +- Add aria-label for notebook cells to improve screen-reader visibility [#10762](https://github.com/jupyterlab/jupyterlab/pull/10762) ([@KrishnaKumarHariprasannan](https://github.com/KrishnaKumarHariprasannan)) +- Yet another fix for Verdaccio publish [#10759](https://github.com/jupyterlab/jupyterlab/pull/10759) ([@afshin](https://github.com/afshin)) +- Refactor apputils widgets [#10758](https://github.com/jupyterlab/jupyterlab/pull/10758) ([@fcollonval](https://github.com/fcollonval)) +- Another Fix to Verdaccio Publishing [#10747](https://github.com/jupyterlab/jupyterlab/pull/10747) ([@afshin](https://github.com/afshin)) +- Fixes for Branch Integrity [#10744](https://github.com/jupyterlab/jupyterlab/pull/10744) ([@afshin](https://github.com/afshin)) +- Fix Verdaccio Publish [#10743](https://github.com/jupyterlab/jupyterlab/pull/10743) ([@afshin](https://github.com/afshin)) +- More Cleanup of Automated Release Process [#10742](https://github.com/jupyterlab/jupyterlab/pull/10742) ([@blink1073](https://github.com/blink1073)) +- Update changelog in master to reflect 3.1 final [#10710](https://github.com/jupyterlab/jupyterlab/pull/10710) ([@blink1073](https://github.com/blink1073)) +- Add branch integrity handling [#10708](https://github.com/jupyterlab/jupyterlab/pull/10708) ([@afshin](https://github.com/afshin)) +- Forward port changelog entries for 3.1.1 and 3.1.2 [#10774](https://github.com/jupyterlab/jupyterlab/pull/10774) ([@blink1073](https://github.com/blink1073)) +- Revert move @types/react in devDependencies of apputils [#10719](https://github.com/jupyterlab/jupyterlab/pull/10719) ([@loichuder](https://github.com/loichuder)) +- Move @types/react in devDependencies of apputils [#10717](https://github.com/jupyterlab/jupyterlab/pull/10717) ([@loichuder](https://github.com/loichuder)) + +### Documentation improvements + +- Fix documentation of the `selectionExecuted` signal [#10778](https://github.com/jupyterlab/jupyterlab/pull/10778) ([@i-aki-y](https://github.com/i-aki-y)) +- Refactor apputils widgets [#10758](https://github.com/jupyterlab/jupyterlab/pull/10758) ([@fcollonval](https://github.com/fcollonval)) +- Document multiple commands single shortcut functionality [#10754](https://github.com/jupyterlab/jupyterlab/pull/10754) ([@richardkang112](https://github.com/richardkang112)) +- Minor improvement to contributing documentation [#10713](https://github.com/jupyterlab/jupyterlab/pull/10713) ([@KrishnaKumarHariprasannan](https://github.com/KrishnaKumarHariprasannan)) +- Add branch integrity handling [#10708](https://github.com/jupyterlab/jupyterlab/pull/10708) ([@afshin](https://github.com/afshin)) +- Added Table of contents (toc.rst) to user guide documentation [#10699](https://github.com/jupyterlab/jupyterlab/pull/10699) ([@AnudeepGunukula](https://github.com/AnudeepGunukula)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-07-27&to=2021-08-06&type=c)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-07-27..2021-08-06&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-07-27..2021-08-06&type=Issues) | [@AnudeepGunukula](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AAnudeepGunukula+updated%3A2021-07-27..2021-08-06&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-07-27..2021-08-06&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-07-27..2021-08-06&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-07-27..2021-08-06&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-07-27..2021-08-06&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-07-27..2021-08-06&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-07-27..2021-08-06&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-07-27..2021-08-06&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-07-27..2021-08-06&type=Issues) | [@i-aki-y](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ai-aki-y+updated%3A2021-07-27..2021-08-06&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-07-27..2021-08-06&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-07-27..2021-08-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-07-27..2021-08-06&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-07-27..2021-08-06&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-07-27..2021-08-06&type=Issues) | [@KrishnaKumarHariprasannan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AKrishnaKumarHariprasannan+updated%3A2021-07-27..2021-08-06&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-07-27..2021-08-06&type=Issues) | [@manfromjupyter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amanfromjupyter+updated%3A2021-07-27..2021-08-06&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-07-27..2021-08-06&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-07-27..2021-08-06&type=Issues) | [@richardkang112](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arichardkang112+updated%3A2021-07-27..2021-08-06&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-07-27..2021-08-06&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-07-27..2021-08-06&type=Issues) + +## v3.4 + +## 3.4.5 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.4...385ea4be3d3e65e1f62d82e8bfedbe554736b2bb)) + +### 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 + +- 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)) +- 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)) +- 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 + +- Log launcher error to console [#12909](https://github.com/jupyterlab/jupyterlab/pull/12909) ([@trungleduc](https://github.com/trungleduc)) + +### 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)) +- Remove reference to unmaintained nb_conda_kernels [#12878](https://github.com/jupyterlab/jupyterlab/pull/12878) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.3...998cf0e146fdb7c61c42d9487ebb89c16581faf8)) + +### Enhancements made + +- Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@jweill-aws](https://github.com/jweill-aws)) +- Increase title width in simple mode [#11546](https://github.com/jupyterlab/jupyterlab/pull/11546) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Bump xtermjs to latest [#12715](https://github.com/jupyterlab/jupyterlab/pull/12715) ([@yuvipanda](https://github.com/yuvipanda)) +- Debugger: Make kernel source list react based [#12751](https://github.com/jupyterlab/jupyterlab/pull/12751) ([@vidartf](https://github.com/vidartf)) +- 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 + +- 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)) +- 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)) +- Pin nbclassic below 0.4.0 [#12767](https://github.com/jupyterlab/jupyterlab/pull/12767) ([@fcollonval](https://github.com/fcollonval)) +- Set focus when active cell changes only from mouse click [#12735](https://github.com/jupyterlab/jupyterlab/pull/12735) ([@fcollonval](https://github.com/fcollonval)) +- Fix staging/yarn.lock registry [#12742](https://github.com/jupyterlab/jupyterlab/pull/12742) ([@vidartf](https://github.com/vidartf)) +- Debugger: Fix CSS for variables inspecting [#12749](https://github.com/jupyterlab/jupyterlab/pull/12749) ([@martinRenou](https://github.com/martinRenou)) +- 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)) +- 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 + +- 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)) +- Bump moment from 2.29.2 to 2.29.4 [#12781](https://github.com/jupyterlab/jupyterlab/pull/12781) ([@dependabot[bot]](https://github.com/apps/dependabot)) +- [memory-leaks] Fixes following cell addition analysis [#12774](https://github.com/jupyterlab/jupyterlab/pull/12774) ([@fcollonval](https://github.com/fcollonval)) +- Bump @lumino/widgets to 1.33.0 [#12777](https://github.com/jupyterlab/jupyterlab/pull/12777) ([@fcollonval](https://github.com/fcollonval)) +- 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)) +- Drop pre-commit from build dependencies (#12680) [#12706](https://github.com/jupyterlab/jupyterlab/pull/12706) ([@jtpio](https://github.com/jtpio)) + +### Documentation improvements + +- Adds version maintenance policy [#12829](https://github.com/jupyterlab/jupyterlab/pull/12829) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +([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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.2...b05da6fae42dcf5a5ad0dd9b46a8b75d64804799)) + +### New features added + +- Persistent side-by-side ratio setting [#12633](https://github.com/jupyterlab/jupyterlab/pull/12633) ([@echarles](https://github.com/echarles)) + +### 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 + +- 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)) +- Fix the side-by-side cell resize handle [#12611](https://github.com/jupyterlab/jupyterlab/pull/12611) ([@echarles](https://github.com/echarles)) +- Fix loading toolbar factory twice [#12599](https://github.com/jupyterlab/jupyterlab/pull/12599) ([@fcollonval](https://github.com/fcollonval)) +- Fixes behavior of `maxNumberOutputs` [#12598](https://github.com/jupyterlab/jupyterlab/pull/12598) ([@fcollonval](https://github.com/fcollonval)) +- Focus not set when clicking on cell margin [#12447](https://github.com/jupyterlab/jupyterlab/pull/12447) ([@fcollonval](https://github.com/fcollonval)) +- 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 + +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.1...1c8f008679c49e74d8a4ee3c6aa0782dfa6a1d35)) + +### 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 + +- Update dependency version [#12535](https://github.com/jupyterlab/jupyterlab/pull/12535) ([@karlaspuldaro](https://github.com/karlaspuldaro)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.4.0...d8d94b351da08181d4d5e0493539c0eb082a1516)) + +### 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 + +- 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 + +- 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 + +([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.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) ([@jweill-aws](https://github.com/jweill-aws)) +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@jweill-aws](https://github.com/jweill-aws)) +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +- 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)) +- Allow downstream extension to set toolbar layout [#12503](https://github.com/jupyterlab/jupyterlab/pull/12503) ([@fcollonval](https://github.com/fcollonval)) +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Creates cell-toolbar, cell-toolbar-extension packages and populates toolbar [#12028](https://github.com/jupyterlab/jupyterlab/pull/12028) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +- 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)) +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- 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-05-03&type=c)) + +[@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2022-04-15..2022-05-03&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2022-04-15..2022-05-03&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2022-04-15..2022-05-03&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2022-04-15..2022-05-03&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2022-04-15..2022-05-03&type=Issues) | [@gabalafou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agabalafou+updated%3A2022-04-15..2022-05-03&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2022-04-15..2022-05-03&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2022-04-15..2022-05-03&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2022-04-15..2022-05-03&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2022-04-15..2022-05-03&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2022-04-15..2022-05-03&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2022-04-15..2022-05-03&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2022-04-15..2022-05-03&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2022-04-15..2022-05-03&type=Issues) + +## v3.3 + +## 3.3.4 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.3...a8a438b3bd84806b8e186e7e037d73167d371c3a)) + +### 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 + +- 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)) +- Add parent header to input reply kernel message [#12376](https://github.com/jupyterlab/jupyterlab/pull/12376) ([@davidbrochart](https://github.com/davidbrochart)) +- fix run cells breaking on non-header markdown cells [#12027](https://github.com/jupyterlab/jupyterlab/pull/12027) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Fix debugger extension error when notebooks is closed quickly [#12396](https://github.com/jupyterlab/jupyterlab/pull/12396) ([@fcollonval](https://github.com/fcollonval)) +- Changes Vega class name to match source code [#12378](https://github.com/jupyterlab/jupyterlab/pull/12378) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +- 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 + +- Fix GitHub link [#12410](https://github.com/jupyterlab/jupyterlab/pull/12410) ([@fcollonval](https://github.com/fcollonval)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.2...d97ff7161640634f69e70b184b9e255a68620f95)) + +### 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) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +- 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)) +- Allow linear and radial gradient [#12276](https://github.com/jupyterlab/jupyterlab/pull/12276) ([@krassowski](https://github.com/krassowski)) +- Don't rely on search results to filter installed extension [#12249](https://github.com/jupyterlab/jupyterlab/pull/12249) ([@fcollonval](https://github.com/fcollonval)) +- Fix directory not found error when preferred_dir is set [#12220](https://github.com/jupyterlab/jupyterlab/pull/12220) ([@andrewfulton9](https://github.com/andrewfulton9)) +- 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 + +- [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 + +- [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) ([@jweill-aws](https://github.com/jweill-aws)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.1...5abe7f69837af8c349d5448f6f3e70db6c48c6e0)) + +### Bugs fixed + +- Remove use of ipython_genutils [#12202](https://github.com/jupyterlab/jupyterlab/pull/12202) ([@blink1073](https://github.com/blink1073)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.3.0...a51e1110263c28211ed9e8e0a4bba247c828af94)) + +### 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Export KernelConnection [#12156](https://github.com/jupyterlab/jupyterlab/pull/12156) ([@tkrabel-db](https://github.com/tkrabel-db)) + +### 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 + +- Adds warning that RTC is experimental [#12171](https://github.com/jupyterlab/jupyterlab/pull/12171) ([@jweill-aws](https://github.com/jweill-aws)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.5...6e484f89df73e09c29e8608e5eca88fa48cc4267)) + +### 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)) +- Support dynamic toolbar definition [#12078](https://github.com/jupyterlab/jupyterlab/pull/12078) ([@fcollonval](https://github.com/fcollonval)) +- Debounce kernel sources filter [#12068](https://github.com/jupyterlab/jupyterlab/pull/12068) ([@fcollonval](https://github.com/fcollonval)) +- Settings UI gives an unreadable JSON dump [#12064](https://github.com/jupyterlab/jupyterlab/pull/12064) ([@fcollonval](https://github.com/fcollonval)) +- Polish settings editor [#12061](https://github.com/jupyterlab/jupyterlab/pull/12061) ([@fcollonval](https://github.com/fcollonval)) +- Show pause on exception button when not available and change caption â€Ļ [#12005](https://github.com/jupyterlab/jupyterlab/pull/12005) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Fix contrast in dark theme of settings editor [#12004](https://github.com/jupyterlab/jupyterlab/pull/12004) ([@krassowski](https://github.com/krassowski)) +- Fix for kernel reconnect [#11952](https://github.com/jupyterlab/jupyterlab/pull/11952) ([@3coins](https://github.com/3coins)) +- Add settings UI [#11977](https://github.com/jupyterlab/jupyterlab/pull/11977) ([@fcollonval](https://github.com/fcollonval)) +- Show the kernel sources as a debugger tab and allow the user to break in kernel sources [#11954](https://github.com/jupyterlab/jupyterlab/pull/11954) ([@echarles](https://github.com/echarles)) +- Enable not showing editor for read-only Markdown cells [#11950](https://github.com/jupyterlab/jupyterlab/pull/11950) ([@fcollonval](https://github.com/fcollonval)) +- Add side-by-side margin override in the notebookConfig [#11880](https://github.com/jupyterlab/jupyterlab/pull/11880) ([@echarles](https://github.com/echarles)) +- Add additional `Accel Enter` keyboard shortcuts for the `notebook:run-cell` command [#11942](https://github.com/jupyterlab/jupyterlab/pull/11942) ([@jtpio](https://github.com/jtpio)) +- Add execution progress indicator [#11941](https://github.com/jupyterlab/jupyterlab/pull/11941) ([@trungleduc](https://github.com/trungleduc)) +- Allow to link factory to file type when adding it [#11540](https://github.com/jupyterlab/jupyterlab/pull/11540) ([@fcollonval](https://github.com/fcollonval)) +- Pause on exception [#11923](https://github.com/jupyterlab/jupyterlab/pull/11923) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Increase color contrast in input boxes [#11922](https://github.com/jupyterlab/jupyterlab/pull/11922) ([@fcollonval](https://github.com/fcollonval)) +- Add startMode setting to define the startup mode [#11881](https://github.com/jupyterlab/jupyterlab/pull/11881) ([@echarles](https://github.com/echarles)) +- Update variable renderer panels [#11874](https://github.com/jupyterlab/jupyterlab/pull/11874) ([@fcollonval](https://github.com/fcollonval)) +- Allow extensions and users to customize easily toolbar items. [#11873](https://github.com/jupyterlab/jupyterlab/pull/11873) ([@fcollonval](https://github.com/fcollonval)) +- Add debugger variable renderer based on mime type [#11871](https://github.com/jupyterlab/jupyterlab/pull/11871) ([@fcollonval](https://github.com/fcollonval)) +- Add a command to open a file from a URL [#11870](https://github.com/jupyterlab/jupyterlab/pull/11870) ([@fcollonval](https://github.com/fcollonval)) +- List workspaces [#11869](https://github.com/jupyterlab/jupyterlab/pull/11869) ([@fcollonval](https://github.com/fcollonval)) +- Add closeOnExit terminal option [#11868](https://github.com/jupyterlab/jupyterlab/pull/11868) ([@fcollonval](https://github.com/fcollonval)) +- Mentions pip3 for macOS users in docs [#11848](https://github.com/jupyterlab/jupyterlab/pull/11848) ([@jweill-aws](https://github.com/jweill-aws)) +- Toc running cell indicator [#11804](https://github.com/jupyterlab/jupyterlab/pull/11804) ([@andrewfulton9](https://github.com/andrewfulton9)) +- 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 + +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Fix: Select kernal text (when open a no kernal .ipynb file) is not translated correctly (#12133) [#12135](https://github.com/jupyterlab/jupyterlab/pull/12135) ([@yangql176](https://github.com/yangql176)) +- Opening keyboard shortcuts UI result in "destruction" of shortcut settings [#12112](https://github.com/jupyterlab/jupyterlab/pull/12112) ([@fcollonval](https://github.com/fcollonval)) +- Fix error rendering in Advanced Settings Editor [#12107](https://github.com/jupyterlab/jupyterlab/pull/12107) ([@krassowski](https://github.com/krassowski)) +- Fix json schema for kernel status settings [#11451](https://github.com/jupyterlab/jupyterlab/pull/11451) ([@fcollonval](https://github.com/fcollonval)) +- Remove toolbar factory setting trick in the tests [#12096](https://github.com/jupyterlab/jupyterlab/pull/12096) ([@jtpio](https://github.com/jtpio)) +- Log error on open document widget. [#12080](https://github.com/jupyterlab/jupyterlab/pull/12080) ([@trungleduc](https://github.com/trungleduc)) +- update status to unkown when kernel is shutdown from running kernels tab [#12083](https://github.com/jupyterlab/jupyterlab/pull/12083) ([@akshaychitneni](https://github.com/akshaychitneni)) +- Handle shutdown error [#12048](https://github.com/jupyterlab/jupyterlab/pull/12048) ([@Zsailer](https://github.com/Zsailer)) +- use path-like comparison in initialize_templates() [#12024](https://github.com/jupyterlab/jupyterlab/pull/12024) ([@kellyyke](https://github.com/kellyyke)) +- Fix misaligned icon and checkbox of setting editor [#11976](https://github.com/jupyterlab/jupyterlab/pull/11976) ([@trungleduc](https://github.com/trungleduc)) +- overrides.json definition takes precedence [#11610](https://github.com/jupyterlab/jupyterlab/pull/11610) ([@fcollonval](https://github.com/fcollonval)) +- Adjust z-index of execution progress tooltip [#11973](https://github.com/jupyterlab/jupyterlab/pull/11973) ([@Sync271](https://github.com/Sync271)) +- Fix the debug modules model #11967 [#11968](https://github.com/jupyterlab/jupyterlab/pull/11968) ([@echarles](https://github.com/echarles)) +- Fix autocomplete in console [#11949](https://github.com/jupyterlab/jupyterlab/pull/11949) ([@fcollonval](https://github.com/fcollonval)) +- fix(docprovider): fix issue with empty notebook [#11901](https://github.com/jupyterlab/jupyterlab/pull/11901) ([@entropitor](https://github.com/entropitor)) +- Ensure a single modal is opened in case of time conflict savings [#11883](https://github.com/jupyterlab/jupyterlab/pull/11883) ([@echarles](https://github.com/echarles)) +- Restore line number state when stopping debugger [#11768](https://github.com/jupyterlab/jupyterlab/pull/11768) ([@fcollonval](https://github.com/fcollonval)) +- Backport PR #11852 on branch 3.3.x (Add percent decoding to username) [#11865](https://github.com/jupyterlab/jupyterlab/pull/11865) ([@fcollonval](https://github.com/fcollonval)) +- Fix Handling of WebSocket Startup Errors [#11358](https://github.com/jupyterlab/jupyterlab/pull/11358) ([@blink1073](https://github.com/blink1073)) +- 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 + +- 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)) +- Partly backport PR #11388 on branch 3.3.x (Add update galata snapshot step) [#11927](https://github.com/jupyterlab/jupyterlab/pull/11927) ([@fcollonval](https://github.com/fcollonval)) +- 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 [#11867](https://github.com/jupyterlab/jupyterlab/pull/11867) ([@fcollonval](https://github.com/fcollonval)) +- Drop support for Python 3.6 [#11740](https://github.com/jupyterlab/jupyterlab/pull/11740) ([@jtpio](https://github.com/jtpio)) +- 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 [#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 + +- Fix broken link in docs [#12138](https://github.com/jupyterlab/jupyterlab/pull/12138) ([@jweill-aws](https://github.com/jweill-aws)) +- Fix anchors and myst configuration [#12063](https://github.com/jupyterlab/jupyterlab/pull/12063) ([@fcollonval](https://github.com/fcollonval)) +- docs: fix shell command with unquoted '>' [#12002](https://github.com/jupyterlab/jupyterlab/pull/12002) ([@ErikBjare](https://github.com/ErikBjare)) +- Update screenshots and text for user interface docs [#11982](https://github.com/jupyterlab/jupyterlab/pull/11982) ([@fcollonval](https://github.com/fcollonval)) +- Update several extensions readme files to delete old content. [#11947](https://github.com/jupyterlab/jupyterlab/pull/11947) ([@jasongrout](https://github.com/jasongrout)) +- Remove theme cookiecutter from the docs [#11928](https://github.com/jupyterlab/jupyterlab/pull/11928) ([@jtpio](https://github.com/jtpio)) +- Allow extensions and users to customize easily toolbar items. [#11873](https://github.com/jupyterlab/jupyterlab/pull/11873) ([@fcollonval](https://github.com/fcollonval)) +- Mentions pip3 for macOS users in docs [#11848](https://github.com/jupyterlab/jupyterlab/pull/11848) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +- 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 + +### 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)) + +[@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2021-12-10..2022-03-02&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-12-10..2022-03-02&type=Issues) | [@baggiponte](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abaggiponte+updated%3A2021-12-10..2022-03-02&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-12-10..2022-03-02&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-12-10..2022-03-02&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ACarreau+updated%3A2021-12-10..2022-03-02&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-12-10..2022-03-02&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-12-10..2022-03-02&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-12-10..2022-03-02&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-12-10..2022-03-02&type=Issues) | [@ErikBjare](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AErikBjare+updated%3A2021-12-10..2022-03-02&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-12-10..2022-03-02&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-12-10..2022-03-02&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-12-10..2022-03-02&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-12-10..2022-03-02&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-12-10..2022-03-02&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-12-10..2022-03-02&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-12-10..2022-03-02&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-12-10..2022-03-02&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-12-10..2022-03-02&type=Issues) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+updated%3A2021-12-10..2022-03-02&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-12-10..2022-03-02&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2021-12-10..2022-03-02&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-12-10..2022-03-02&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-12-10..2022-03-02&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2021-12-10..2022-03-02&type=Issues) | [@schmidi314](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aschmidi314+updated%3A2021-12-10..2022-03-02&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-12-10..2022-03-02&type=Issues) | [@Sync271](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASync271+updated%3A2021-12-10..2022-03-02&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2021-12-10..2022-03-02&type=Issues) | [@thesinepainter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Athesinepainter+updated%3A2021-12-10..2022-03-02&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-12-10..2022-03-02&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-12-10..2022-03-02&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-12-10..2022-03-02&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AZsailer+updated%3A2021-12-10..2022-03-02&type=Issues) + +## v3.2 + +## 3.2.9 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.8...dbfc96a51c872288f16b7340398bf99a3df14b1f)) + +### 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 + +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.7...b2402e5b9e0db0416b5f0e5ac29c9104a69f0c83)) + +### 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 + +([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 + +No merged PRs + +## 3.2.6 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.5...ebce458c5e55126a7cbd5082f669446269007a34)) + +### 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 + +- 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)) +- Fix handling of disabled extensions [#11744](https://github.com/jupyterlab/jupyterlab/pull/11744) ([@jtpio](https://github.com/jtpio)) +- Update debugger icon css to work with white panel background [#11688](https://github.com/jupyterlab/jupyterlab/pull/11688) ([@andrewfulton9](https://github.com/andrewfulton9)) +- 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 + +- 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 + +- Triage documentation [#11661](https://github.com/jupyterlab/jupyterlab/pull/11661) ([@jweill-aws](https://github.com/jweill-aws)) +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.4...97b8069f014c51f584c86165ec0aff8c98be99cb)) + +### 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 + +- 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)) +- Increase notebook-cell margin in side-by-side mode [#11539](https://github.com/jupyterlab/jupyterlab/pull/11539) ([@jess-x](https://github.com/jess-x)) +- Support file type extension with upper case [#11526](https://github.com/jupyterlab/jupyterlab/pull/11526) ([@fcollonval](https://github.com/fcollonval)) +- Sync dirty property between clients [#11525](https://github.com/jupyterlab/jupyterlab/pull/11525) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix markdown benchmark snapshot [#11575](https://github.com/jupyterlab/jupyterlab/pull/11575) ([@fcollonval](https://github.com/fcollonval)) +- Cell YModel: Fix setAttachment method [#11529](https://github.com/jupyterlab/jupyterlab/pull/11529) ([@martinRenou](https://github.com/martinRenou)) +- Allow cross-file anchors with leading number [#11517](https://github.com/jupyterlab/jupyterlab/pull/11517) ([@loichuder](https://github.com/loichuder)) +- Update ModelDB metadata when switching the shared model [#11493](https://github.com/jupyterlab/jupyterlab/pull/11493) ([@hbcarlos](https://github.com/hbcarlos)) +- Connecting `toggleCollapsedSignal` to handler right at creation of Markdown [#11514](https://github.com/jupyterlab/jupyterlab/pull/11514) ([@fcollonval](https://github.com/fcollonval)) +- Update `sanitize-html` pin to 3.5.3 [#11513](https://github.com/jupyterlab/jupyterlab/pull/11513) ([@fcollonval](https://github.com/fcollonval)) +- Only show the head of the outputs and ensure iopub outputs are correctly displayed [#11502](https://github.com/jupyterlab/jupyterlab/pull/11502) ([@fcollonval](https://github.com/fcollonval)) +- 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 + +- 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)) +- postcss 8.4.0 breaks integrity 2 CI test [#11552](https://github.com/jupyterlab/jupyterlab/pull/11552) ([@fcollonval](https://github.com/fcollonval)) +- Bump tmpl from 1.0.4 to 1.0.5 [#11512](https://github.com/jupyterlab/jupyterlab/pull/11512) ([@dependabot[bot]](https://github.com/dependabot)) +- Increase notebook markdown test robustness [#11524](https://github.com/jupyterlab/jupyterlab/pull/11524) ([@fcollonval](https://github.com/fcollonval)) +- Bump semver-regex from 3.1.2 to 3.1.3 [#11511](https://github.com/jupyterlab/jupyterlab/pull/11511) ([@dependabot[bot]](https://github.com/dependabot)) +- 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 + +- Missing parenthesis [#11590](https://github.com/jupyterlab/jupyterlab/pull/11590) ([@davidbrochart](https://github.com/davidbrochart)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.3...3bf36235a2521944b2b0b034e7986630ee83de18)) + +### 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 + +- 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)) +- Regenerate server connection settings for printing [#11454](https://github.com/jupyterlab/jupyterlab/pull/11454) ([@mbektas](https://github.com/mbektas)) +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.2...49b2dfa5b74d5139dcbc55940ee5ed93b48e9db2)) + +### Enhancements made + +- [3.2.x] Expose `window.jupyterapp` [#11417](https://github.com/jupyterlab/jupyterlab/pull/11417) ([@jtpio](https://github.com/jtpio)) + +### 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 + +- Backport PR #11420 on branch 3.2.x (Makes ILabShell optional in toc extension) [#11421](https://github.com/jupyterlab/jupyterlab/pull/11421) ([@jweill-aws](https://github.com/jweill-aws)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.1...0fcd2f5bfbe857a416dfad0c177f3f1299fef96e)) + +### 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)) +- Fix for terminal theme style [#11291](https://github.com/jupyterlab/jupyterlab/pull/11291) ([@3coins](https://github.com/3coins)) +- 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 + +- 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 + +- 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) ([@jweill-aws](https://github.com/jweill-aws)) +- Recommend providing screenshots for translators [#11357](https://github.com/jupyterlab/jupyterlab/pull/11357) ([@krassowski](https://github.com/krassowski)) +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.2.0...2b7e4ea681ad11b2df16124b588448aac9562aef)) + +### 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)) +- Added handling of `'\r'` ended files [#11310](https://github.com/jupyterlab/jupyterlab/pull/11310) ([@lucabarcelos](https://github.com/lucabarcelos)) +- 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 + +- Pass version spec as an input [#11322](https://github.com/jupyterlab/jupyterlab/pull/11322) ([@jtpio](https://github.com/jtpio)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/@jupyterlab/example-services-outputarea@3.1.9...2444ed0588adba1999a5575304d452a3b512c913)) + +### 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/latest/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)) +- Make check margin between last modified timestamps on disk and client configurable [#11153](https://github.com/jupyterlab/jupyterlab/pull/11153) ([@ph-ph](https://github.com/ph-ph)) +- Reuse cell id of cut cell on cut + paste [#11138](https://github.com/jupyterlab/jupyterlab/pull/11138) ([@smacke](https://github.com/smacke)) +- Add Side-by-side Rendering [#11143](https://github.com/jupyterlab/jupyterlab/pull/11143) ([@blink1073](https://github.com/blink1073)) +- Add show trailing whitespace option to Notebook and Text Editor [#11131](https://github.com/jupyterlab/jupyterlab/pull/11131) ([@blink1073](https://github.com/blink1073)) +- Implement Restart and debug [#11129](https://github.com/jupyterlab/jupyterlab/pull/11129) ([@blink1073](https://github.com/blink1073)) +- Add `preferred-dir` handling [#10667](https://github.com/jupyterlab/jupyterlab/pull/10667) ([@goanpeca](https://github.com/goanpeca)) +- 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 + +- 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)) +- Use standard hash type in webpack build [#11234](https://github.com/jupyterlab/jupyterlab/pull/11234) ([@blink1073](https://github.com/blink1073)) +- Remove format from fetching options if null [#11229](https://github.com/jupyterlab/jupyterlab/pull/11229) ([@loichuder](https://github.com/loichuder)) +- 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)) +- Fix renaming issue in collaborative mode [#11197](https://github.com/jupyterlab/jupyterlab/pull/11197) ([@dmonad](https://github.com/dmonad)) +- Restore workspace and open tree path [#11176](https://github.com/jupyterlab/jupyterlab/pull/11176) ([@blink1073](https://github.com/blink1073)) +- Share notebook's metadata [#11064](https://github.com/jupyterlab/jupyterlab/pull/11064) ([@hbcarlos](https://github.com/hbcarlos)) +- Normalize notebook cell line endings to `\n` [#11141](https://github.com/jupyterlab/jupyterlab/pull/11141) ([@jasongrout](https://github.com/jasongrout)) +- 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 + +- 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)) +- 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)) +- Check `i18n` will pass on zeroed patch pre-release version [#11214](https://github.com/jupyterlab/jupyterlab/pull/11214) ([@fcollonval](https://github.com/fcollonval)) +- Refactor `window.open` to make it work also in desktop app [#11202](https://github.com/jupyterlab/jupyterlab/pull/11202) ([@mbektas](https://github.com/mbektas)) +- Rename "JupyterLab Theme" to "Theme" [#11198](https://github.com/jupyterlab/jupyterlab/pull/11198) ([@jtpio](https://github.com/jtpio)) +- Use only context and id to check i18n [#11190](https://github.com/jupyterlab/jupyterlab/pull/11190) ([@fcollonval](https://github.com/fcollonval)) +- Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) +- Clean up notebook test utils [#11133](https://github.com/jupyterlab/jupyterlab/pull/11133) ([@blink1073](https://github.com/blink1073)) +- Change "Export Notebook As" to "Save and Export Notebook As" [#11132](https://github.com/jupyterlab/jupyterlab/pull/11132) ([@blink1073](https://github.com/blink1073)) +- Make Test Server Configurable [#11015](https://github.com/jupyterlab/jupyterlab/pull/11015) ([@fcollonval](https://github.com/fcollonval)) +- 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 + +- 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 + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-09-01&to=2021-10-14&type=c)) + +[@3coins](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A3coins+updated%3A2021-09-01..2021-10-14&type=Issues) | [@achimgaedke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aachimgaedke+updated%3A2021-09-01..2021-10-14&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-09-01..2021-10-14&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-09-01..2021-10-14&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-09-01..2021-10-14&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-09-01..2021-10-14&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agithub-actions+updated%3A2021-09-01..2021-10-14&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-09-01..2021-10-14&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-09-01..2021-10-14&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-09-01..2021-10-14&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-09-01..2021-10-14&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-09-01..2021-10-14&type=Issues) | [@joelostblom](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajoelostblom+updated%3A2021-09-01..2021-10-14&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-09-01..2021-10-14&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-09-01..2021-10-14&type=Issues) | [@jupyterlab-probot](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-probot+updated%3A2021-09-01..2021-10-14&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-09-01..2021-10-14&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-09-01..2021-10-14&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-09-01..2021-10-14&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-09-01..2021-10-14&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-09-01..2021-10-14&type=Issues) | [@trungleduc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrungleduc+updated%3A2021-09-01..2021-10-14&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-09-01..2021-10-14&type=Issues) + +## v3.1 + +## 3.1.19 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.18...90ed111b152665357b069cf4a42590fe07d630e8)) + +### 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 + +- Pass version spec as an input [#11322](https://github.com/jupyterlab/jupyterlab/pull/11322) ([@jtpio](https://github.com/jtpio)) + +### 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) | [@jweill-aws](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajweill-aws+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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.17...c6dc40f16ea6fd1b5a58167dec6ed066de3304a9)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.16...a899a8b9da2216d91a2426c4956bc2e711a93ecd)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.14...fc00631f2088d90655b0e09a96f14da86a02f911)) + +### 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)) +- Fix renaming issue in collaborative mode [#11197](https://github.com/jupyterlab/jupyterlab/pull/11197) ([@dmonad](https://github.com/dmonad)) +- 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 + +- 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 + +([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 + +(Skipped due to errors in release process) + +## 3.1.14 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.13...fb6df989b70ce096c9769fc728bb158f311b48a9)) + +### 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 + +- Fix the "Edit on GitHub" link [#11149](https://github.com/jupyterlab/jupyterlab/pull/11149) ([@krassowski](https://github.com/krassowski)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.12...a8d8f3dbceb9c852e6196b0ebd368759232e2626)) + +### Enhancements made + +- Fetch translations via the `ServerConnection.ISettings` [#11091](https://github.com/jupyterlab/jupyterlab/pull/11091) ([@jtpio](https://github.com/jtpio)) + +### 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 + +- 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 + +- 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 + +- Remove item from changelog that slips through [#11110](https://github.com/jupyterlab/jupyterlab/pull/11110) ([@fcollonval](https://github.com/fcollonval)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.11...1af92c9bbae0eab61938bbbba0ae8cc5e9b59fdd)) + +### 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 + +- 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 + +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.10...f04391135c11c6c5e3e8c4706ec26e675f0db4d6)) + +### 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)) +- use correct nbformat version - fixes #11005 [#11017](https://github.com/jupyterlab/jupyterlab/pull/11017) ([@dmonad](https://github.com/dmonad)) +- Fix ignored promise leading to incorrect initial tooltip position [#11010](https://github.com/jupyterlab/jupyterlab/pull/11010) ([@krassowski](https://github.com/krassowski)) +- Fix typo in nbformat dialog [#11001](https://github.com/jupyterlab/jupyterlab/pull/11001) ([@davidbrochart](https://github.com/davidbrochart)) +- 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 + +- 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 + +- Update documentation for internationalization [#11024](https://github.com/jupyterlab/jupyterlab/pull/11024) ([@fcollonval](https://github.com/fcollonval)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.9...646b708cdb76f6d0e4e622b0546cc4dc7d2854c7)) + +### 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 + +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.8...8f8cfc548c7c91e9dcf0dc51fd6eafc98f3fcfef)) + +### 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 + +- Correct the documentation for packaging [#10910](https://github.com/jupyterlab/jupyterlab/pull/10910) ([@fcollonval](https://github.com/fcollonval)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.7...ecb8be24857466a69e4643a5a708b29a062d8465)) + +### 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)) +- Improve language choice menu and dialog [#10885](https://github.com/jupyterlab/jupyterlab/pull/10885) ([@krassowski](https://github.com/krassowski)) +- Manual Backport PR #10865 on branch 3.1.x (Add translations for notebook mode name) [#10878](https://github.com/jupyterlab/jupyterlab/pull/10878) ([@krassowski](https://github.com/krassowski)) +- Fix cell type dropdown behaviour in Firefox on 3.1.x branch [#10870](https://github.com/jupyterlab/jupyterlab/pull/10870) ([@krassowski](https://github.com/krassowski)) +- Add missing link in passing translator down to kernel selector [#10864](https://github.com/jupyterlab/jupyterlab/pull/10864) ([@krassowski](https://github.com/krassowski)) +- Fix code names showing up in new translations, add docs [#10860](https://github.com/jupyterlab/jupyterlab/pull/10860) ([@krassowski](https://github.com/krassowski)) +- 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.6...e0a6d74212394a40ba00a12d8043f1b49326f73d)) + +### 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 + +- 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 + +- Fix documentation snippets [#10813](https://github.com/jupyterlab/jupyterlab/pull/10813) ([@fcollonval](https://github.com/fcollonval)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.5...4cec12eba17eaf313241b595e98b40cb0a851e65)) + +### 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 + +- Clean up Link Caching Again [#10794](https://github.com/jupyterlab/jupyterlab/pull/10794) ([@afshin](https://github.com/afshin)) + +### 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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.4...6d14f7f8d3a7400a5fddbbdfaf79d0b8bdd5325f)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.1...be8032d1a932e09f553d0343659e89a6a25a516f)) + +### Enhancements made + +- Normalize translation domain [#10728](https://github.com/jupyterlab/jupyterlab/pull/10728) ([@fcollonval](https://github.com/fcollonval)) + +### 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 + +- 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.1.0...6b09ac27dcde158a2dee9df1499af384fce7086a)) + +### 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 + +- Add branch integrity handling [#10708](https://github.com/jupyterlab/jupyterlab/pull/10708) ([@afshin](https://github.com/afshin)) + +### 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 + +([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 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.6...60f37be54a714c391fad5500cb57055af1492591)) + +### 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/latest/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/latest/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 + +- 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)) +- Debugger: Basic support for evaluating code at a breakpoint [#9930](https://github.com/jupyterlab/jupyterlab/pull/9930) ([@jtpio](https://github.com/jtpio)) +- Notebook: Show a visual indicator that the cell has been edited [#10296](https://github.com/jupyterlab/jupyterlab/pull/10296) ([@martinRenou](https://github.com/martinRenou)) +- Notebook: Find and replace within a single cell [#10067](https://github.com/jupyterlab/jupyterlab/pull/10067) ([@jess-x](https://github.com/jess-x)) +- Notebook: Copy cell output to clipboard [#10282](https://github.com/jupyterlab/jupyterlab/pull/10282) ([@cameron-toy](https://github.com/cameron-toy)) +- Notebook: Add support for collapsing hierarchy of headings [#10260](https://github.com/jupyterlab/jupyterlab/pull/10260) ([@marthacryan](https://github.com/marthacryan)) +- File Browser: Add shortcuts [#10206](https://github.com/jupyterlab/jupyterlab/pull/10206) ([@martinRenou](https://github.com/martinRenou)) +- Table of Contents: Add capacity to skip H1 Headers [#9994](https://github.com/jupyterlab/jupyterlab/pull/9994) ([@skyetim](https://github.com/skyetim)) +- Table of Contents: Add context menus to sections containing runnable code cells [#10167](https://github.com/jupyterlab/jupyterlab/pull/10167) ([@jess-x](https://github.com/jess-x)) +- Completer: Added tab cycling to Completer [#10147](https://github.com/jupyterlab/jupyterlab/pull/10147) ([@cameron-toy](https://github.com/cameron-toy)) +- Customization: Build context menu from settings for easy customization [#10373](https://github.com/jupyterlab/jupyterlab/pull/10373) ([@fcollonval](https://github.com/fcollonval)) +- Customization: Build menus from settings [#10254](https://github.com/jupyterlab/jupyterlab/pull/10254) ([@fcollonval](https://github.com/fcollonval)) +- Customization: Disable `autoClosingBrackets` by default everywhere [#9488](https://github.com/jupyterlab/jupyterlab/pull/9488) ([@telamonian](https://github.com/telamonian)) +- 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 + +- 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)) +- Fixes doc string for toc syncCollapseState setting [#10639](https://github.com/jupyterlab/jupyterlab/pull/10639) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Allow to set custom position for `Tooltip` [#10590](https://github.com/jupyterlab/jupyterlab/pull/10590) ([@krassowski](https://github.com/krassowski)) +- Rename files in collaborative mode [#10564](https://github.com/jupyterlab/jupyterlab/pull/10564) ([@hbcarlos](https://github.com/hbcarlos)) +- Reorganize settings menu for text editor [#10563](https://github.com/jupyterlab/jupyterlab/pull/10563) ([@fcollonval](https://github.com/fcollonval)) +- Add promptCellConfig to Code Console Settings [#10555](https://github.com/jupyterlab/jupyterlab/pull/10555) ([@jess-x](https://github.com/jess-x)) +- communicate heading collapse between ToC and Notebook [#10545](https://github.com/jupyterlab/jupyterlab/pull/10545) ([@andrewfulton9](https://github.com/andrewfulton9)) +- feat: add options to include cell output in headings [#10537](https://github.com/jupyterlab/jupyterlab/pull/10537) ([@skyetim](https://github.com/skyetim)) +- Open inspector split to the right [#10519](https://github.com/jupyterlab/jupyterlab/pull/10519) ([@legendb317](https://github.com/legendb317)) +- Simple mode rename improvements 2.0 [#10518](https://github.com/jupyterlab/jupyterlab/pull/10518) ([@cameron-toy](https://github.com/cameron-toy)) +- Make current kernel the default in kernel selector [#10510](https://github.com/jupyterlab/jupyterlab/pull/10510) ([@gereleth](https://github.com/gereleth)) +- Add selectionExecuted and executionScheduled signals + update executed signal to include error status/info [#10493](https://github.com/jupyterlab/jupyterlab/pull/10493) ([@mwakaba2](https://github.com/mwakaba2)) +- Scroll cell into view after output collapse [#10491](https://github.com/jupyterlab/jupyterlab/pull/10491) ([@gereleth](https://github.com/gereleth)) +- Collaborative renaming & moving of files [#10470](https://github.com/jupyterlab/jupyterlab/pull/10470) ([@dmonad](https://github.com/dmonad)) +- Update inspector open [#10449](https://github.com/jupyterlab/jupyterlab/pull/10449) ([@legendb317](https://github.com/legendb317)) +- dirty cell: Store the code source as true source of output [#10438](https://github.com/jupyterlab/jupyterlab/pull/10438) ([@fcollonval](https://github.com/fcollonval)) +- RTC: Anonymous user names based on the moons of Jupyter [#10411](https://github.com/jupyterlab/jupyterlab/pull/10411) ([@dmonad](https://github.com/dmonad)) +- Add icon for .jl files in explorer [#10397](https://github.com/jupyterlab/jupyterlab/pull/10397) ([@shngt](https://github.com/shngt)) +- Support arrow keys for button navigation [#10349](https://github.com/jupyterlab/jupyterlab/pull/10349) ([@jahn96](https://github.com/jahn96)) +- Feature: select all cells with tags in toc [#10346](https://github.com/jupyterlab/jupyterlab/pull/10346) ([@NPetz](https://github.com/NPetz)) +- [licenses] use serverSettings from serviceManager, style tweaks [#10329](https://github.com/jupyterlab/jupyterlab/pull/10329) ([@bollwyvl](https://github.com/bollwyvl)) +- Filebrowser ContextMenu: Use separators [#10293](https://github.com/jupyterlab/jupyterlab/pull/10293) ([@martinRenou](https://github.com/martinRenou)) +- Add a plugin to be able to swap the doc provider [#10256](https://github.com/jupyterlab/jupyterlab/pull/10256) ([@jtpio](https://github.com/jtpio)) +- Completer: expose `activeIndex` and `indexChanged` [#10244](https://github.com/jupyterlab/jupyterlab/pull/10244) ([@hbcarlos](https://github.com/hbcarlos)) +- DirListing: Refactor selection so that it's based on path not name [#10237](https://github.com/jupyterlab/jupyterlab/pull/10237) ([@martinRenou](https://github.com/martinRenou)) +- DirListing: Allow for no sorting when clicking on headers [#10236](https://github.com/jupyterlab/jupyterlab/pull/10236) ([@martinRenou](https://github.com/martinRenou)) +- Improve error handling in labextension install [#10233](https://github.com/jupyterlab/jupyterlab/pull/10233) ([@akx](https://github.com/akx)) +- FileBrowser: Add protected method for creating the dirlisting [#10216](https://github.com/jupyterlab/jupyterlab/pull/10216) ([@martinRenou](https://github.com/martinRenou)) +- added new command called runAllEnabled [#10215](https://github.com/jupyterlab/jupyterlab/pull/10215) ([@sarahspak](https://github.com/sarahspak)) +- Filebrowser: Allow for escaping renaming [#10205](https://github.com/jupyterlab/jupyterlab/pull/10205) ([@martinRenou](https://github.com/martinRenou)) +- Add new widget area below the dockpanel [#10201](https://github.com/jupyterlab/jupyterlab/pull/10201) ([@fcollonval](https://github.com/fcollonval)) +- Debugger: show button shortcuts in tooltips [#10199](https://github.com/jupyterlab/jupyterlab/pull/10199) ([@jess-x](https://github.com/jess-x)) +- Restore the relative sizes of areas in split panel [#10196](https://github.com/jupyterlab/jupyterlab/pull/10196) ([@krassowski](https://github.com/krassowski)) +- Move open-with to its own plugin, so it can be disabled independently. [#10193](https://github.com/jupyterlab/jupyterlab/pull/10193) ([@robertpyke](https://github.com/robertpyke)) +- key-bindings to codemirror search in single cell [#10184](https://github.com/jupyterlab/jupyterlab/pull/10184) ([@jess-x](https://github.com/jess-x)) +- Rename at file creation [#10181](https://github.com/jupyterlab/jupyterlab/pull/10181) ([@martinRenou](https://github.com/martinRenou)) +- Scroll into view on each step/frame changes/... [#10160](https://github.com/jupyterlab/jupyterlab/pull/10160) ([@mlucool](https://github.com/mlucool)) +- Added support for namespace packages in labextensions. [#10150](https://github.com/jupyterlab/jupyterlab/pull/10150) ([@mellesies](https://github.com/mellesies)) +- Color contrast adjustments for sidebar and command palette [#10146](https://github.com/jupyterlab/jupyterlab/pull/10146) ([@isabela-pf](https://github.com/isabela-pf)) +- Rename simple interface documents from the title widget [#10140](https://github.com/jupyterlab/jupyterlab/pull/10140) ([@cameron-toy](https://github.com/cameron-toy)) +- Perf: Add virtual Notebook for delayed cell rendering [#10131](https://github.com/jupyterlab/jupyterlab/pull/10131) ([@goanpeca](https://github.com/goanpeca)) +- Perf: Trim notebook large output for better performance [#10129](https://github.com/jupyterlab/jupyterlab/pull/10129) ([@goanpeca](https://github.com/goanpeca)) +- Perf: Codemirror performance enhancement [#10128](https://github.com/jupyterlab/jupyterlab/pull/10128) ([@goanpeca](https://github.com/goanpeca)) +- Perf: Update CSS for performance enhancements [#10127](https://github.com/jupyterlab/jupyterlab/pull/10127) ([@goanpeca](https://github.com/goanpeca)) +- Add Skip Link [#10126](https://github.com/jupyterlab/jupyterlab/pull/10126) ([@0618](https://github.com/0618)) +- Allow Use of CDN to be Configurable for Fetching Package Metadata [#10125](https://github.com/jupyterlab/jupyterlab/pull/10125) ([@jhamet93](https://github.com/jhamet93)) +- Allow NPM Registry and CDN Registry to be Configurable [#10110](https://github.com/jupyterlab/jupyterlab/pull/10110) ([@jhamet93](https://github.com/jhamet93)) +- Fix last modified column toggle, allow to set it permanently [#10100](https://github.com/jupyterlab/jupyterlab/pull/10100) ([@krassowski](https://github.com/krassowski)) +- TOC current position [#10099](https://github.com/jupyterlab/jupyterlab/pull/10099) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Add 'merge cell above/below' commands with shortcuts [#10076](https://github.com/jupyterlab/jupyterlab/pull/10076) ([@krassowska](https://github.com/krassowska)) +- Disable escape key and click-outside-dialog behaviors if hasClose = false [#10049](https://github.com/jupyterlab/jupyterlab/pull/10049) ([@DianeHu](https://github.com/DianeHu)) +- Name (un-renamed) file on first save [#10043](https://github.com/jupyterlab/jupyterlab/pull/10043) ([@jess-x](https://github.com/jess-x)) +- Improve UX when a user restarts their Notebook server via JupyterHub [#10032](https://github.com/jupyterlab/jupyterlab/pull/10032) ([@vkaidalov-rft](https://github.com/vkaidalov-rft)) +- Create New commands for common file types associated with available kernels [#10009](https://github.com/jupyterlab/jupyterlab/pull/10009) ([@ohrely](https://github.com/ohrely)) +- feat: CommandLinker Support in Markdown cells [#9909](https://github.com/jupyterlab/jupyterlab/pull/9909) ([@0618](https://github.com/0618)) +- Add support for Gitpod editor [#9883](https://github.com/jupyterlab/jupyterlab/pull/9883) ([@saulshanabrook](https://github.com/saulshanabrook)) +- Move documentation panel rendering to renderer [#9663](https://github.com/jupyterlab/jupyterlab/pull/9663) ([@krassowski](https://github.com/krassowski)) +- transition header element to div.header for accessibility [#9648](https://github.com/jupyterlab/jupyterlab/pull/9648) ([@tonyfast](https://github.com/tonyfast)) +- Add aria roles and labels [#9622](https://github.com/jupyterlab/jupyterlab/pull/9622) ([@marthacryan](https://github.com/marthacryan)) +- Vertical notebook cell prompts on mobile [#9464](https://github.com/jupyterlab/jupyterlab/pull/9464) ([@jtpio](https://github.com/jtpio)) +- Debugger keyboard shortcuts [#9154](https://github.com/jupyterlab/jupyterlab/pull/9154) ([@mnowacki-b](https://github.com/mnowacki-b)) +- Implement a guard for pending user input to avoid deadlocks [#8713](https://github.com/jupyterlab/jupyterlab/pull/8713) ([@echarles](https://github.com/echarles)) +- Add null fileformat [#7596](https://github.com/jupyterlab/jupyterlab/pull/7596) ([@telamonian](https://github.com/telamonian)) +- 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 + +- 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)) +- Add icon and mnemonic menu attributes in settings [#10678](https://github.com/jupyterlab/jupyterlab/pull/10678) ([@fcollonval](https://github.com/fcollonval)) +- Restore the focus target check removed in #10517 [#10664](https://github.com/jupyterlab/jupyterlab/pull/10664) ([@krassowski](https://github.com/krassowski)) +- Fixed event handler in debugger session test [#10651](https://github.com/jupyterlab/jupyterlab/pull/10651) ([@JohanMabille](https://github.com/JohanMabille)) +- Fix #10391 - incorrect cursor position after autocomplete [#10647](https://github.com/jupyterlab/jupyterlab/pull/10647) ([@dmonad](https://github.com/dmonad)) +- Fix error messages when creating new dirs/files in a read only dir [#10641](https://github.com/jupyterlab/jupyterlab/pull/10641) ([@vkaidalov-rft](https://github.com/vkaidalov-rft)) +- More automated release fixes [#10621](https://github.com/jupyterlab/jupyterlab/pull/10621) ([@blink1073](https://github.com/blink1073)) +- Disable autoclosing brackets by default in console [#10612](https://github.com/jupyterlab/jupyterlab/pull/10612) ([@jasongrout](https://github.com/jasongrout)) +- Restore current sidebar widget even if sides are switched [#10605](https://github.com/jupyterlab/jupyterlab/pull/10605) ([@afshin](https://github.com/afshin)) +- Save only workspace name as metadata.id instead of full path [#10603](https://github.com/jupyterlab/jupyterlab/pull/10603) ([@afshin](https://github.com/afshin)) +- Invoke onCellInserted when rendering a placeholder cell [#10602](https://github.com/jupyterlab/jupyterlab/pull/10602) ([@echarles](https://github.com/echarles)) +- Fix font-weight for collaborative cursor caret [#10598](https://github.com/jupyterlab/jupyterlab/pull/10598) ([@krassowski](https://github.com/krassowski)) +- Do not show tooltip when completer is active [#10588](https://github.com/jupyterlab/jupyterlab/pull/10588) ([@krassowski](https://github.com/krassowski)) +- Only save and use valid user settings for the editor [#10585](https://github.com/jupyterlab/jupyterlab/pull/10585) ([@jasongrout](https://github.com/jasongrout)) +- Remove `tabIndex` taking focus away from notebook [#10580](https://github.com/jupyterlab/jupyterlab/pull/10580) ([@krassowski](https://github.com/krassowski)) +- Open Help menu's Jupyter Forum in a new browser tab by default [#10574](https://github.com/jupyterlab/jupyterlab/pull/10574) ([@isabela-pf](https://github.com/isabela-pf)) +- Move all child cells when collapsed markdown heading is moved [#10571](https://github.com/jupyterlab/jupyterlab/pull/10571) ([@marthacryan](https://github.com/marthacryan)) +- Restore JupyterLabMenu missing `menu` attribute [#10567](https://github.com/jupyterlab/jupyterlab/pull/10567) ([@fcollonval](https://github.com/fcollonval)) +- Completer: Do not announce subset match selection if it did not change [#10556](https://github.com/jupyterlab/jupyterlab/pull/10556) ([@krassowski](https://github.com/krassowski)) +- Fix string variable in debugger tree view [#10550](https://github.com/jupyterlab/jupyterlab/pull/10550) ([@fcollonval](https://github.com/fcollonval)) +- Fix dialog windows ignoring buttons focus [#10532](https://github.com/jupyterlab/jupyterlab/pull/10532) ([@krassowski](https://github.com/krassowski)) +- 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)) +- 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)) +- Fix watch mode [#10444](https://github.com/jupyterlab/jupyterlab/pull/10444) ([@fcollonval](https://github.com/fcollonval)) +- Restore maxNumberOutputs removed in #10131 [#10432](https://github.com/jupyterlab/jupyterlab/pull/10432) ([@krassowski](https://github.com/krassowski)) +- Fix console error when closing notebook [#10426](https://github.com/jupyterlab/jupyterlab/pull/10426) ([@marthacryan](https://github.com/marthacryan)) +- Focus on "Cancel" rather than "Delete" in delete dialog [#10400](https://github.com/jupyterlab/jupyterlab/pull/10400) ([@krassowski](https://github.com/krassowski)) +- Fix the `docmanager:name-on-save` command [#10355](https://github.com/jupyterlab/jupyterlab/pull/10355) ([@jtpio](https://github.com/jtpio)) +- Fix codemirror options updating [#10353](https://github.com/jupyterlab/jupyterlab/pull/10353) ([@jasongrout](https://github.com/jasongrout)) +- Fix incomplete transition to .path from .name [#10281](https://github.com/jupyterlab/jupyterlab/pull/10281) ([@krassowski](https://github.com/krassowski)) +- Fix filebrowser focus issue [#10280](https://github.com/jupyterlab/jupyterlab/pull/10280) ([@krassowski](https://github.com/krassowski)) +- Bump marked.js (and types) to pull fix for rendering [#10274](https://github.com/jupyterlab/jupyterlab/pull/10274) ([@krassowski](https://github.com/krassowski)) +- Fix autocompletion issue [#10234](https://github.com/jupyterlab/jupyterlab/pull/10234) ([@dmonad](https://github.com/dmonad)) +- show user dialog when attempting folder drop [#10209](https://github.com/jupyterlab/jupyterlab/pull/10209) ([@dharmaquark](https://github.com/dharmaquark)) +- Workaround Chromium issue with iframe reload/href [#10185](https://github.com/jupyterlab/jupyterlab/pull/10185) ([@krassowski](https://github.com/krassowski)) +- Upgrade CodeMirror to 5.61.0 (fixes indentation for Python type hints) [#10175](https://github.com/jupyterlab/jupyterlab/pull/10175) ([@krassowski](https://github.com/krassowski)) +- fix document count in title [#10168](https://github.com/jupyterlab/jupyterlab/pull/10168) ([@jess-x](https://github.com/jess-x)) +- Debugger: Remove all breakpoints should confirm action first [#10161](https://github.com/jupyterlab/jupyterlab/pull/10161) ([@mlucool](https://github.com/mlucool)) +- fix: highlight tab focused buttons and Dir List [#10153](https://github.com/jupyterlab/jupyterlab/pull/10153) ([@0618](https://github.com/0618)) +- Fix handling of mathjax in notebook example [#10134](https://github.com/jupyterlab/jupyterlab/pull/10134) ([@jtpio](https://github.com/jtpio)) +- Fix dry run logic in publish script [#10068](https://github.com/jupyterlab/jupyterlab/pull/10068) ([@jtpio](https://github.com/jtpio)) +- Fix #7525 by setting yarn.lock permissions [#10063](https://github.com/jupyterlab/jupyterlab/pull/10063) ([@jluttine](https://github.com/jluttine)) +- Add cell id per notebook format 4.5 [#10018](https://github.com/jupyterlab/jupyterlab/pull/10018) ([@jayqi](https://github.com/jayqi)) +- [Fix] `Copy shareable link` command - fix the filename encoding (for files with spaces in the name) [#10015](https://github.com/jupyterlab/jupyterlab/pull/10015) ([@ognjenjevremovic](https://github.com/ognjenjevremovic)) +- fixed ellipsis character after menu items in UI [#10000](https://github.com/jupyterlab/jupyterlab/pull/10000) ([@RodyLipson](https://github.com/RodyLipson)) +- Fix js-apputils session context tests [#9997](https://github.com/jupyterlab/jupyterlab/pull/9997) ([@jtpio](https://github.com/jtpio)) +- Fix escaping of urls and paths [#9978](https://github.com/jupyterlab/jupyterlab/pull/9978) ([@jasongrout](https://github.com/jasongrout)) +- Do not make unnecessary npm registry requests [#9974](https://github.com/jupyterlab/jupyterlab/pull/9974) ([@jasongrout](https://github.com/jasongrout)) +- Remove lookbehind from ToC MD regex for Safari [#9962](https://github.com/jupyterlab/jupyterlab/pull/9962) ([@dge8](https://github.com/dge8)) +- DocRegistry FileType pattern matching doesn't work [#9958](https://github.com/jupyterlab/jupyterlab/pull/9958) ([@ajbozarth](https://github.com/ajbozarth)) +- Made disposable optional for widget extensions [#9954](https://github.com/jupyterlab/jupyterlab/pull/9954) ([@loichuder](https://github.com/loichuder)) +- Fix ToC markdown bug for HTML comments [#9938](https://github.com/jupyterlab/jupyterlab/pull/9938) ([@marthacryan](https://github.com/marthacryan)) +- Make Table of Contents extension not rewrite all notebook headers. [#9932](https://github.com/jupyterlab/jupyterlab/pull/9932) ([@jasongrout](https://github.com/jasongrout)) +- Fix watch mode for external extensions [#9915](https://github.com/jupyterlab/jupyterlab/pull/9915) ([@ajbozarth](https://github.com/ajbozarth)) +- Add websocket token auth in case of different ws domain [#9898](https://github.com/jupyterlab/jupyterlab/pull/9898) ([@darcsoel](https://github.com/darcsoel)) +- Bug fix for extension watch mode behavior [#9889](https://github.com/jupyterlab/jupyterlab/pull/9889) ([@afshin](https://github.com/afshin)) +- Do not display the splash screen in the application state plugin [#9875](https://github.com/jupyterlab/jupyterlab/pull/9875) ([@jasongrout](https://github.com/jasongrout)) +- Allow overrides.json to override default shortcuts. [#9858](https://github.com/jupyterlab/jupyterlab/pull/9858) ([@jasongrout](https://github.com/jasongrout)) +- Fix contrast of debugger icon when selected [#9851](https://github.com/jupyterlab/jupyterlab/pull/9851) ([@krassowski](https://github.com/krassowski)) +- Remove the previous file_to_run logic [#9847](https://github.com/jupyterlab/jupyterlab/pull/9847) ([@jtpio](https://github.com/jtpio)) +- Add missing return types to fileeditor-extension/src/commands.ts [#9844](https://github.com/jupyterlab/jupyterlab/pull/9844) ([@jtpio](https://github.com/jtpio)) +- Fix example pins, don't prettier ipynb_checkpoints [#9835](https://github.com/jupyterlab/jupyterlab/pull/9835) ([@bollwyvl](https://github.com/bollwyvl)) +- Remove the auto-switch to “mobile” mode, and behavior switches associated with mobile mode [#9831](https://github.com/jupyterlab/jupyterlab/pull/9831) ([@jasongrout](https://github.com/jasongrout)) +- Fix the display of breakpoints on restore [#9824](https://github.com/jupyterlab/jupyterlab/pull/9824) ([@jtpio](https://github.com/jtpio)) +- @jupyterlab/rendermime: upgraded `marked` dep past vulnerability [#9809](https://github.com/jupyterlab/jupyterlab/pull/9809) ([@telamonian](https://github.com/telamonian)) +- Fix Services Tests [#9806](https://github.com/jupyterlab/jupyterlab/pull/9806) ([@afshin](https://github.com/afshin)) +- Fix label for "Create Console for Editor" [#9794](https://github.com/jupyterlab/jupyterlab/pull/9794) ([@krassowski](https://github.com/krassowski)) +- Fix mimerender test example and test in CI [#9782](https://github.com/jupyterlab/jupyterlab/pull/9782) ([@afshin](https://github.com/afshin)) +- Correct synchronization of tags between metadata and tags widget [#9773](https://github.com/jupyterlab/jupyterlab/pull/9773) ([@fcollonval](https://github.com/fcollonval)) +- Fix race condition in session startup [#9766](https://github.com/jupyterlab/jupyterlab/pull/9766) ([@afshin](https://github.com/afshin)) +- [BugFix] `ArgumentConflict` is not defined [#9760](https://github.com/jupyterlab/jupyterlab/pull/9760) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Fix search provider not recognising text nodes [#9746](https://github.com/jupyterlab/jupyterlab/pull/9746) ([@krassowski](https://github.com/krassowski)) +- Do not take focus away from search panel (for navigateToCurrentDirectory) [#9745](https://github.com/jupyterlab/jupyterlab/pull/9745) ([@krassowski](https://github.com/krassowski)) +- Fix uninstallation of packages in extension manager [#9744](https://github.com/jupyterlab/jupyterlab/pull/9744) ([@afshin](https://github.com/afshin)) +- Add missing default_url fields to more examples [#9737](https://github.com/jupyterlab/jupyterlab/pull/9737) ([@afshin](https://github.com/afshin)) +- Add missing default_url fields to examples [#9731](https://github.com/jupyterlab/jupyterlab/pull/9731) ([@afshin](https://github.com/afshin)) +- Fix debug flag handling in build command [#9715](https://github.com/jupyterlab/jupyterlab/pull/9715) ([@afshin](https://github.com/afshin)) +- 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 + +- 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)) +- Fix integrity2 test [#10660](https://github.com/jupyterlab/jupyterlab/pull/10660) ([@fcollonval](https://github.com/fcollonval)) +- Context menu plugin schema [#10645](https://github.com/jupyterlab/jupyterlab/pull/10645) ([@jtpio](https://github.com/jtpio)) +- Move the context menu building logic to a separate plugin [#10624](https://github.com/jupyterlab/jupyterlab/pull/10624) ([@jtpio](https://github.com/jtpio)) +- Fix typo in the `dirty` plugin id [#10623](https://github.com/jupyterlab/jupyterlab/pull/10623) ([@jtpio](https://github.com/jtpio)) +- More releaser fixes [#10614](https://github.com/jupyterlab/jupyterlab/pull/10614) ([@afshin](https://github.com/afshin)) +- Revert name file feature [#10609](https://github.com/jupyterlab/jupyterlab/pull/10609) ([@jess-x](https://github.com/jess-x)) +- Fix usage of Releaser [#10608](https://github.com/jupyterlab/jupyterlab/pull/10608) ([@afshin](https://github.com/afshin)) +- Finish Releaser Integration [#10606](https://github.com/jupyterlab/jupyterlab/pull/10606) ([@afshin](https://github.com/afshin)) +- Fix `js-services` test with the new ipykernel 6 [#10592](https://github.com/jupyterlab/jupyterlab/pull/10592) ([@jtpio](https://github.com/jtpio)) +- Switch to using a `PromiseDelegate` in `yprovider.ts` [#10587](https://github.com/jupyterlab/jupyterlab/pull/10587) ([@jtpio](https://github.com/jtpio)) +- Rename to `YjsEchoWebSocket` [#10586](https://github.com/jupyterlab/jupyterlab/pull/10586) ([@jtpio](https://github.com/jtpio)) +- Give answered issues action permission to write [#10583](https://github.com/jupyterlab/jupyterlab/pull/10583) ([@jasongrout](https://github.com/jasongrout)) +- Update typedoc [#10582](https://github.com/jupyterlab/jupyterlab/pull/10582) ([@jasongrout](https://github.com/jasongrout)) +- Set the stale message to have an actual value. [#10575](https://github.com/jupyterlab/jupyterlab/pull/10575) ([@jasongrout](https://github.com/jasongrout)) +- Move the application status check to a separate plugin [#10572](https://github.com/jupyterlab/jupyterlab/pull/10572) ([@jtpio](https://github.com/jtpio)) +- Skip the ipykernel debugger test [#10569](https://github.com/jupyterlab/jupyterlab/pull/10569) ([@jtpio](https://github.com/jtpio)) +- Add new file to CodeQL `path-ignore` [#10568](https://github.com/jupyterlab/jupyterlab/pull/10568) ([@jtpio](https://github.com/jtpio)) +- Fix closing answered issues by setting the stale-issue-message attribute [#10553](https://github.com/jupyterlab/jupyterlab/pull/10553) ([@jasongrout](https://github.com/jasongrout)) +- Switch to dev-mode for ui-tests [#10549](https://github.com/jupyterlab/jupyterlab/pull/10549) ([@fcollonval](https://github.com/fcollonval)) +- Export awareness [#10539](https://github.com/jupyterlab/jupyterlab/pull/10539) ([@hbcarlos](https://github.com/hbcarlos)) +- Move answered workflow file to the workflows directory [#10536](https://github.com/jupyterlab/jupyterlab/pull/10536) ([@jasongrout](https://github.com/jasongrout)) +- Update skiplink implementation [#10535](https://github.com/jupyterlab/jupyterlab/pull/10535) ([@isabela-pf](https://github.com/isabela-pf)) +- DirListing: Make mouse events methods protected [#10527](https://github.com/jupyterlab/jupyterlab/pull/10527) ([@martinRenou](https://github.com/martinRenou)) +- Refresh yarn.lock in preparation for 3.1 [#10516](https://github.com/jupyterlab/jupyterlab/pull/10516) ([@jasongrout](https://github.com/jasongrout)) +- Update webpack dependency [#10515](https://github.com/jupyterlab/jupyterlab/pull/10515) ([@jasongrout](https://github.com/jasongrout)) +- Carry end-to-end tests on docker [#10498](https://github.com/jupyterlab/jupyterlab/pull/10498) ([@fcollonval](https://github.com/fcollonval)) +- Add language to MarkdownCodeBlocks' "should find a block with a language" spec [#10495](https://github.com/jupyterlab/jupyterlab/pull/10495) ([@ainzzorl](https://github.com/ainzzorl)) +- Add Verdaccio helper to prepare for releaser [#10494](https://github.com/jupyterlab/jupyterlab/pull/10494) ([@jtpio](https://github.com/jtpio)) +- Make highlighted line in debugger readable [#10479](https://github.com/jupyterlab/jupyterlab/pull/10479) ([@krassowski](https://github.com/krassowski)) +- Move filebrowser shortcuts to settings [#10466](https://github.com/jupyterlab/jupyterlab/pull/10466) ([@fcollonval](https://github.com/fcollonval)) +- upgrade to galata 3.0.11-2 [#10453](https://github.com/jupyterlab/jupyterlab/pull/10453) ([@mbektas](https://github.com/mbektas)) +- UI fix: clearer save message [#10430](https://github.com/jupyterlab/jupyterlab/pull/10430) ([@jess-x](https://github.com/jess-x)) +- Interface pass on the name file dialog feature [#10416](https://github.com/jupyterlab/jupyterlab/pull/10416) ([@jtpio](https://github.com/jtpio)) +- Split move cell test into 2 separate tests [#10410](https://github.com/jupyterlab/jupyterlab/pull/10410) ([@fcollonval](https://github.com/fcollonval)) +- Fix a bug since merging arrow navigation between buttons in Dialog (#10349) [#10395](https://github.com/jupyterlab/jupyterlab/pull/10395) ([@jahn96](https://github.com/jahn96)) +- Handle updating dependencies without a semver range prefix [#10393](https://github.com/jupyterlab/jupyterlab/pull/10393) ([@jasongrout](https://github.com/jasongrout)) +- Restore padding on main dock panel [#10390](https://github.com/jupyterlab/jupyterlab/pull/10390) ([@fcollonval](https://github.com/fcollonval)) +- Add the `ui-tests` folder to the labeler [#10386](https://github.com/jupyterlab/jupyterlab/pull/10386) ([@jtpio](https://github.com/jtpio)) +- Fix completer on cell example [#10382](https://github.com/jupyterlab/jupyterlab/pull/10382) ([@hbcarlos](https://github.com/hbcarlos)) +- UI Tests: Update reference screenshots [#10372](https://github.com/jupyterlab/jupyterlab/pull/10372) ([@jtpio](https://github.com/jtpio)) +- Remove `mode` from the `JupyterFrontEnd.IShell` interface [#10368](https://github.com/jupyterlab/jupyterlab/pull/10368) ([@jtpio](https://github.com/jtpio)) +- Allow bumpversion to work with patch [#10360](https://github.com/jupyterlab/jupyterlab/pull/10360) ([@blink1073](https://github.com/blink1073)) +- Start testing the debugger with Galata [#10359](https://github.com/jupyterlab/jupyterlab/pull/10359) ([@jtpio](https://github.com/jtpio)) +- Remove unused `IMainMenu` dependency [#10356](https://github.com/jupyterlab/jupyterlab/pull/10356) ([@jtpio](https://github.com/jtpio)) +- tagging deprecated completer APIs [#10348](https://github.com/jupyterlab/jupyterlab/pull/10348) ([@dharmaquark](https://github.com/dharmaquark)) +- Fix master UI test [#10345](https://github.com/jupyterlab/jupyterlab/pull/10345) ([@fcollonval](https://github.com/fcollonval)) +- Add linter rule for sorting import [#10344](https://github.com/jupyterlab/jupyterlab/pull/10344) ([@fcollonval](https://github.com/fcollonval)) +- Update labeler to use the `documentation` label for docs [#10336](https://github.com/jupyterlab/jupyterlab/pull/10336) ([@jtpio](https://github.com/jtpio)) +- Fix clean-package and correct toc extension [#10332](https://github.com/jupyterlab/jupyterlab/pull/10332) ([@fcollonval](https://github.com/fcollonval)) +- Automated UI testing using Galata [#10331](https://github.com/jupyterlab/jupyterlab/pull/10331) ([@mbektas](https://github.com/mbektas)) +- Add permissions to the labeler workflow [#10324](https://github.com/jupyterlab/jupyterlab/pull/10324) ([@jtpio](https://github.com/jtpio)) +- Fix labeler workflow [#10322](https://github.com/jupyterlab/jupyterlab/pull/10322) ([@jtpio](https://github.com/jtpio)) +- fix: remove the 3-second startup delay of the kernel connection [#10321](https://github.com/jupyterlab/jupyterlab/pull/10321) ([@mariobuikhuizen](https://github.com/mariobuikhuizen)) +- Update `ws` dependency [#10316](https://github.com/jupyterlab/jupyterlab/pull/10316) ([@jtpio](https://github.com/jtpio)) +- Fix remote-caret rendering [#10315](https://github.com/jupyterlab/jupyterlab/pull/10315) ([@dmonad](https://github.com/dmonad)) +- Add Plugin wrapper for "Open in New Browser Tab" so it can be disabled. [#10311](https://github.com/jupyterlab/jupyterlab/pull/10311) ([@robertpyke](https://github.com/robertpyke)) +- Minor code style pass on `yprovider.ts` [#10308](https://github.com/jupyterlab/jupyterlab/pull/10308) ([@jtpio](https://github.com/jtpio)) +- Update labeler and add auto assign to PRs [#10306](https://github.com/jupyterlab/jupyterlab/pull/10306) ([@goanpeca](https://github.com/goanpeca)) +- Fix focus accept button on dialog unit test [#10303](https://github.com/jupyterlab/jupyterlab/pull/10303) ([@fcollonval](https://github.com/fcollonval)) +- Add Yjs as a singleton package [#10301](https://github.com/jupyterlab/jupyterlab/pull/10301) ([@dmonad](https://github.com/dmonad)) +- Remove various tab indices [#10289](https://github.com/jupyterlab/jupyterlab/pull/10289) ([@marthacryan](https://github.com/marthacryan)) +- Add the new docprovider-extension to the labeler [#10288](https://github.com/jupyterlab/jupyterlab/pull/10288) ([@jtpio](https://github.com/jtpio)) +- FileBrowserModel: Allow for overwriting \_onFileChanged [#10286](https://github.com/jupyterlab/jupyterlab/pull/10286) ([@martinRenou](https://github.com/martinRenou)) +- Enable real time collaboration on the dev Binder [#10258](https://github.com/jupyterlab/jupyterlab/pull/10258) ([@jtpio](https://github.com/jtpio)) +- Add the new packages to the labeler [#10257](https://github.com/jupyterlab/jupyterlab/pull/10257) ([@jtpio](https://github.com/jtpio)) +- Update enhancement tag in the issue template [#10253](https://github.com/jupyterlab/jupyterlab/pull/10253) ([@jtpio](https://github.com/jtpio)) +- DirListing: Make some methods protected [#10247](https://github.com/jupyterlab/jupyterlab/pull/10247) ([@martinRenou](https://github.com/martinRenou)) +- FileBrowserModel: Make some methods protected [#10246](https://github.com/jupyterlab/jupyterlab/pull/10246) ([@martinRenou](https://github.com/martinRenou)) +- FileBrowser: Make listing and crumbs accessible to subclasses [#10245](https://github.com/jupyterlab/jupyterlab/pull/10245) ([@martinRenou](https://github.com/martinRenou)) +- Fix Shutdown Error in Test App [#10240](https://github.com/jupyterlab/jupyterlab/pull/10240) ([@afshin](https://github.com/afshin)) +- Remove tabmanager-extension from packages list [#10232](https://github.com/jupyterlab/jupyterlab/pull/10232) ([@krassowski](https://github.com/krassowski)) +- Re-enable splice source tests [#10230](https://github.com/jupyterlab/jupyterlab/pull/10230) ([@jtpio](https://github.com/jtpio)) +- DirListing: Make Renderer's private method protected [#10224](https://github.com/jupyterlab/jupyterlab/pull/10224) ([@martinRenou](https://github.com/martinRenou)) +- Update to `sanitize-html~=2.3.3` [#10220](https://github.com/jupyterlab/jupyterlab/pull/10220) ([@jtpio](https://github.com/jtpio)) +- Update to `url-parse~=1.5.1` [#10219](https://github.com/jupyterlab/jupyterlab/pull/10219) ([@jtpio](https://github.com/jtpio)) +- Remove runtime dependency on `jupyter_packaging` [#10217](https://github.com/jupyterlab/jupyterlab/pull/10217) ([@jtpio](https://github.com/jtpio)) +- Replaced ... with ellipses unicode character in .ts files [#10208](https://github.com/jupyterlab/jupyterlab/pull/10208) ([@yasmin-bb](https://github.com/yasmin-bb)) +- add tooltip on cell type dropdown [#10182](https://github.com/jupyterlab/jupyterlab/pull/10182) ([@fcollonval](https://github.com/fcollonval)) +- Update the mock packages to jupyter-packaging 0.10 [#10177](https://github.com/jupyterlab/jupyterlab/pull/10177) ([@jtpio](https://github.com/jtpio)) +- clean up unused signal in notebook search [#10169](https://github.com/jupyterlab/jupyterlab/pull/10169) ([@jess-x](https://github.com/jess-x)) +- Debugger: show callstack clearer with names/ids [#10162](https://github.com/jupyterlab/jupyterlab/pull/10162) ([@mlucool](https://github.com/mlucool)) +- Fix Permissions of Labeler Workflow [#10141](https://github.com/jupyterlab/jupyterlab/pull/10141) ([@jtpio](https://github.com/jtpio)) +- Add Required Permission to CodeQL Workflow [#10138](https://github.com/jupyterlab/jupyterlab/pull/10138) ([@afshin](https://github.com/afshin)) +- Clean up workflow permissions [#10136](https://github.com/jupyterlab/jupyterlab/pull/10136) ([@afshin](https://github.com/afshin)) +- include all default\*.json in @jupyterlab/testutils distributions [#10132](https://github.com/jupyterlab/jupyterlab/pull/10132) ([@bollwyvl](https://github.com/bollwyvl)) +- Clean up package integrity [#10122](https://github.com/jupyterlab/jupyterlab/pull/10122) ([@jtpio](https://github.com/jtpio)) +- Update employer name [#10120](https://github.com/jupyterlab/jupyterlab/pull/10120) ([@mbektas](https://github.com/mbektas)) +- Export createRendermimePlugin from @jupyterlab/application [#10117](https://github.com/jupyterlab/jupyterlab/pull/10117) ([@jtpio](https://github.com/jtpio)) +- Upgrade to Jupyter Packaging 0.9 [#10096](https://github.com/jupyterlab/jupyterlab/pull/10096) ([@jtpio](https://github.com/jtpio)) +- Pulled notebook export UI into separate extension so it can be disabled easily [#10094](https://github.com/jupyterlab/jupyterlab/pull/10094) ([@DianeHu](https://github.com/DianeHu)) +- Add a clarifying comment for the download plugin. [#10092](https://github.com/jupyterlab/jupyterlab/pull/10092) ([@jasongrout](https://github.com/jasongrout)) +- Move the about help dialog to its own plugin [#10089](https://github.com/jupyterlab/jupyterlab/pull/10089) ([@jtpio](https://github.com/jtpio)) +- Move "Launch Classic Notebook" to its own plugin [#10086](https://github.com/jupyterlab/jupyterlab/pull/10086) ([@jtpio](https://github.com/jtpio)) +- Add the celltags extension to the `app` example [#10078](https://github.com/jupyterlab/jupyterlab/pull/10078) ([@jtpio](https://github.com/jtpio)) +- Move the main application commands to a separate plugin [#10073](https://github.com/jupyterlab/jupyterlab/pull/10073) ([@jtpio](https://github.com/jtpio)) +- Pull out filebrowser context menu download UI into separate plugin so it can be disabled easily [#10066](https://github.com/jupyterlab/jupyterlab/pull/10066) ([@DianeHu](https://github.com/DianeHu)) +- Pull docmanager download UI into separate plugin so that it can be disabled easily [#10065](https://github.com/jupyterlab/jupyterlab/pull/10065) ([@DianeHu](https://github.com/DianeHu)) +- Add the toc extension to the `app` example [#10053](https://github.com/jupyterlab/jupyterlab/pull/10053) ([@jtpio](https://github.com/jtpio)) +- Update copyright to 2021 in the about dialog [#10052](https://github.com/jupyterlab/jupyterlab/pull/10052) ([@jtpio](https://github.com/jtpio)) +- Remove `buffer` dependency from `@jupyterlab/apputils` [#10050](https://github.com/jupyterlab/jupyterlab/pull/10050) ([@jtpio](https://github.com/jtpio)) +- Use blobs to set the svg source of an image in the image viewer [#10029](https://github.com/jupyterlab/jupyterlab/pull/10029) ([@jasongrout](https://github.com/jasongrout)) +- Show app.name in the tab title [#10023](https://github.com/jupyterlab/jupyterlab/pull/10023) ([@jtpio](https://github.com/jtpio)) +- Add document name and workspaces to title Bar [#10002](https://github.com/jupyterlab/jupyterlab/pull/10002) ([@jess-x](https://github.com/jess-x)) +- Loosen pin on jupyter-packaging [#9998](https://github.com/jupyterlab/jupyterlab/pull/9998) ([@afshin](https://github.com/afshin)) +- Move js-services to the flaky CI workflow [#9987](https://github.com/jupyterlab/jupyterlab/pull/9987) ([@jtpio](https://github.com/jtpio)) +- API for custom toolbars/headers in Notebook widgets [#9984](https://github.com/jupyterlab/jupyterlab/pull/9984) ([@fasiha](https://github.com/fasiha)) +- Use Playwright and Test All Browsers [#9977](https://github.com/jupyterlab/jupyterlab/pull/9977) ([@afshin](https://github.com/afshin)) +- Update console message for when fullMathjaxUrl is missing from the page config [#9970](https://github.com/jupyterlab/jupyterlab/pull/9970) ([@jtpio](https://github.com/jtpio)) +- Update react-json-tree to 0.15.0 [#9949](https://github.com/jupyterlab/jupyterlab/pull/9949) ([@jtpio](https://github.com/jtpio)) +- changing ... to ellipsis character in json find [#9946](https://github.com/jupyterlab/jupyterlab/pull/9946) ([@RodyLipson](https://github.com/RodyLipson)) +- Update @lumino dependencies [#9939](https://github.com/jupyterlab/jupyterlab/pull/9939) ([@marthacryan](https://github.com/marthacryan)) +- Move the code consoles functionalities for the notebook to a separate plugin [#9934](https://github.com/jupyterlab/jupyterlab/pull/9934) ([@jtpio](https://github.com/jtpio)) +- Remove the explicit path to the mock extension used in the integrity script [#9921](https://github.com/jupyterlab/jupyterlab/pull/9921) ([@jtpio](https://github.com/jtpio)) +- Automatically close “answered” issues if they have no activity for 30 days [#9920](https://github.com/jupyterlab/jupyterlab/pull/9920) ([@jasongrout](https://github.com/jasongrout)) +- Added Pipfile to .gitignore [#9893](https://github.com/jupyterlab/jupyterlab/pull/9893) ([@palewire](https://github.com/palewire)) +- Added Forum to help menu. Fixes #8678 [#9892](https://github.com/jupyterlab/jupyterlab/pull/9892) ([@palewire](https://github.com/palewire)) +- Make the markdown plugin more reusable [#9876](https://github.com/jupyterlab/jupyterlab/pull/9876) ([@jtpio](https://github.com/jtpio)) +- Turn HTML sanitizer into a plugin [#9873](https://github.com/jupyterlab/jupyterlab/pull/9873) ([@ohrely](https://github.com/ohrely)) +- Cleanup unused Python imports [#9864](https://github.com/jupyterlab/jupyterlab/pull/9864) ([@jtpio](https://github.com/jtpio)) +- Update @lumino dependencies [#9857](https://github.com/jupyterlab/jupyterlab/pull/9857) ([@jtpio](https://github.com/jtpio)) +- Move the cloned outputs to a separate plugin [#9845](https://github.com/jupyterlab/jupyterlab/pull/9845) ([@jtpio](https://github.com/jtpio)) +- Add icon to Create Console for Editor [#9843](https://github.com/jupyterlab/jupyterlab/pull/9843) ([@jtpio](https://github.com/jtpio)) +- Add Markdown icon for Show Markdown Preview [#9840](https://github.com/jupyterlab/jupyterlab/pull/9840) ([@krassowski](https://github.com/krassowski)) +- Enable Caching in Production Minimized Mode [#9833](https://github.com/jupyterlab/jupyterlab/pull/9833) ([@afshin](https://github.com/afshin)) +- Clean up Release Scripts and Test in CI [#9821](https://github.com/jupyterlab/jupyterlab/pull/9821) ([@afshin](https://github.com/afshin)) +- Update CI script timeouts [#9814](https://github.com/jupyterlab/jupyterlab/pull/9814) ([@afshin](https://github.com/afshin)) +- Update MANIFEST.in to include package_data files. [#9780](https://github.com/jupyterlab/jupyterlab/pull/9780) ([@jasongrout](https://github.com/jasongrout)) +- Add hash to webpack requests to enable caching [#9776](https://github.com/jupyterlab/jupyterlab/pull/9776) ([@afshin](https://github.com/afshin)) +- Updates the locking configuration [#9754](https://github.com/jupyterlab/jupyterlab/pull/9754) ([@jasongrout](https://github.com/jasongrout)) +- Use get_package_url from jupyterlab-server [#9743](https://github.com/jupyterlab/jupyterlab/pull/9743) ([@krassowski](https://github.com/krassowski)) +- Add link for prebuilt extensions too [#9702](https://github.com/jupyterlab/jupyterlab/pull/9702) ([@flying-sheep](https://github.com/flying-sheep)) +- Enable jupyter labextension build/watch to work for custom jupyterlab distributions [#9697](https://github.com/jupyterlab/jupyterlab/pull/9697) ([@jasongrout](https://github.com/jasongrout)) +- Move flaky tests to a separate workflow on CI [#9677](https://github.com/jupyterlab/jupyterlab/pull/9677) ([@jtpio](https://github.com/jtpio)) +- 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 + +- 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)) +- fixes doc string for toc syncCollapseState setting [#10639](https://github.com/jupyterlab/jupyterlab/pull/10639) ([@andrewfulton9](https://github.com/andrewfulton9)) +- Mention prebuilt extensions in README and docs [#10604](https://github.com/jupyterlab/jupyterlab/pull/10604) ([@krassowski](https://github.com/krassowski)) +- replace OS X -> macOS [#10599](https://github.com/jupyterlab/jupyterlab/pull/10599) ([@partev](https://github.com/partev)) +- Fix documentation for `selectionExecuted` signal (copy-paste error) [#10579](https://github.com/jupyterlab/jupyterlab/pull/10579) ([@krassowski](https://github.com/krassowski)) +- Documentation for Real Time Collaboration [#10547](https://github.com/jupyterlab/jupyterlab/pull/10547) ([@hbcarlos](https://github.com/hbcarlos)) +- Update docs [#10543](https://github.com/jupyterlab/jupyterlab/pull/10543) ([@hbcarlos](https://github.com/hbcarlos)) +- Fix a few typos, camelCase some privates [#10524](https://github.com/jupyterlab/jupyterlab/pull/10524) ([@krassowski](https://github.com/krassowski)) +- Add `ipykernel` to the debugger user docs [#10512](https://github.com/jupyterlab/jupyterlab/pull/10512) ([@jtpio](https://github.com/jtpio)) +- Fix two links in documentation [#10421](https://github.com/jupyterlab/jupyterlab/pull/10421) ([@blink1073](https://github.com/blink1073)) +- Allow theme and style css [#10381](https://github.com/jupyterlab/jupyterlab/pull/10381) ([@jasongrout](https://github.com/jasongrout)) +- Revert visual regression [#10376](https://github.com/jupyterlab/jupyterlab/pull/10376) ([@fcollonval](https://github.com/fcollonval)) +- Build context menu from settings for easy customization [#10373](https://github.com/jupyterlab/jupyterlab/pull/10373) ([@fcollonval](https://github.com/fcollonval)) +- Fix listing documentation [#10367](https://github.com/jupyterlab/jupyterlab/pull/10367) ([@fcollonval](https://github.com/fcollonval)) +- add UI testing section to contributor documentation [#10364](https://github.com/jupyterlab/jupyterlab/pull/10364) ([@mbektas](https://github.com/mbektas)) +- Add missing docstrings [#10357](https://github.com/jupyterlab/jupyterlab/pull/10357) ([@jtpio](https://github.com/jtpio)) +- changed Javsacript to Javascript [#10333](https://github.com/jupyterlab/jupyterlab/pull/10333) ([@Ashish-15s](https://github.com/Ashish-15s)) +- Fix clean-package and correct toc extension [#10332](https://github.com/jupyterlab/jupyterlab/pull/10332) ([@fcollonval](https://github.com/fcollonval)) +- Automated UI testing using Galata [#10331](https://github.com/jupyterlab/jupyterlab/pull/10331) ([@mbektas](https://github.com/mbektas)) +- fix: typo in getting_started/faq [#10330](https://github.com/jupyterlab/jupyterlab/pull/10330) ([@manavendrasen](https://github.com/manavendrasen)) +- Fix documentation [#10323](https://github.com/jupyterlab/jupyterlab/pull/10323) ([@davidbrochart](https://github.com/davidbrochart)) +- Update Maintainer List [#10300](https://github.com/jupyterlab/jupyterlab/pull/10300) ([@blink1073](https://github.com/blink1073)) +- Add note about symlink activation on Windows. [#10292](https://github.com/jupyterlab/jupyterlab/pull/10292) ([@fcollonval](https://github.com/fcollonval)) +- Add changelog entry for 3.0.16 [#10267](https://github.com/jupyterlab/jupyterlab/pull/10267) ([@blink1073](https://github.com/blink1073)) +- Update `documentsearch` description in `package.json` [#10265](https://github.com/jupyterlab/jupyterlab/pull/10265) ([@jtpio](https://github.com/jtpio)) +- Build menus from settings [#10254](https://github.com/jupyterlab/jupyterlab/pull/10254) ([@fcollonval](https://github.com/fcollonval)) +- Add changelog entry for 3.0.15 release [#10238](https://github.com/jupyterlab/jupyterlab/pull/10238) ([@blink1073](https://github.com/blink1073)) +- Update contribution docs to show how to rebuild on change [#10204](https://github.com/jupyterlab/jupyterlab/pull/10204) ([@martinRenou](https://github.com/martinRenou)) +- Remove installing `notebook` from the contributing guide [#10200](https://github.com/jupyterlab/jupyterlab/pull/10200) ([@jtpio](https://github.com/jtpio)) +- Improve prebuild extension docs [#10190](https://github.com/jupyterlab/jupyterlab/pull/10190) ([@hbcarlos](https://github.com/hbcarlos)) +- fix(docs): corrects typo in ui-components README [#10155](https://github.com/jupyterlab/jupyterlab/pull/10155) ([@plan-do-break-fix](https://github.com/plan-do-break-fix)) +- Update packaging commands in the extension tutorial [#10104](https://github.com/jupyterlab/jupyterlab/pull/10104) ([@jtpio](https://github.com/jtpio)) +- Mention mamba as a means to install JupyterLab [#10093](https://github.com/jupyterlab/jupyterlab/pull/10093) ([@SylvainCorlay](https://github.com/SylvainCorlay)) +- Fix changelog links for 3.0.13 [#10085](https://github.com/jupyterlab/jupyterlab/pull/10085) ([@blink1073](https://github.com/blink1073)) +- Update changelog in master for 3.0.14 [#10082](https://github.com/jupyterlab/jupyterlab/pull/10082) ([@blink1073](https://github.com/blink1073)) +- Fix typo in ui-components's README [#10062](https://github.com/jupyterlab/jupyterlab/pull/10062) ([@martinRenou](https://github.com/martinRenou)) +- Fix changelog links [#10060](https://github.com/jupyterlab/jupyterlab/pull/10060) ([@blink1073](https://github.com/blink1073)) +- Forward port changelog entries [#10058](https://github.com/jupyterlab/jupyterlab/pull/10058) ([@blink1073](https://github.com/blink1073)) +- chore: update extension_tutorial [#10026](https://github.com/jupyterlab/jupyterlab/pull/10026) ([@0618](https://github.com/0618)) +- Add Ability Use Source Directories in App Dir [#10024](https://github.com/jupyterlab/jupyterlab/pull/10024) ([@afshin](https://github.com/afshin)) +- Use check-links-ignore to ignore pulls and issues [#10012](https://github.com/jupyterlab/jupyterlab/pull/10012) ([@afshin](https://github.com/afshin)) +- Clarify where the overrides.json file should be in the docs [#9989](https://github.com/jupyterlab/jupyterlab/pull/9989) ([@jasongrout](https://github.com/jasongrout)) +- Move Changelog to Standard Location [#9944](https://github.com/jupyterlab/jupyterlab/pull/9944) ([@afshin](https://github.com/afshin)) +- Point the CI badges in the README to master branch [#9919](https://github.com/jupyterlab/jupyterlab/pull/9919) ([@blink1073](https://github.com/blink1073)) +- Update changelog for 3.0.9 and 3.0.10 [#9917](https://github.com/jupyterlab/jupyterlab/pull/9917) ([@jasongrout](https://github.com/jasongrout)) +- Update link to JupyterLab Demo Binder [#9872](https://github.com/jupyterlab/jupyterlab/pull/9872) ([@afshin](https://github.com/afshin)) +- Add link to source extension list of metadata in prebuilt extensions [#9860](https://github.com/jupyterlab/jupyterlab/pull/9860) ([@bsyouness](https://github.com/bsyouness)) +- fix release_test, squash all non-eslint CI warnings [#9854](https://github.com/jupyterlab/jupyterlab/pull/9854) ([@bollwyvl](https://github.com/bollwyvl)) +- Convert Changelog to Markdown [#9846](https://github.com/jupyterlab/jupyterlab/pull/9846) ([@afshin](https://github.com/afshin)) +- Update changelog for 3.0.8 [#9805](https://github.com/jupyterlab/jupyterlab/pull/9805) ([@blink1073](https://github.com/blink1073)) +- Link to file with lab CSS variables [#9788](https://github.com/jupyterlab/jupyterlab/pull/9788) ([@yuvipanda](https://github.com/yuvipanda)) +- Add "author_name" to cookiecutter [#9783](https://github.com/jupyterlab/jupyterlab/pull/9783) ([@janjagusch](https://github.com/janjagusch)) +- Update extension_dev.rst [#9728](https://github.com/jupyterlab/jupyterlab/pull/9728) ([@stadlerb](https://github.com/stadlerb)) +- Update changelog for 3.0.7 [#9722](https://github.com/jupyterlab/jupyterlab/pull/9722) ([@blink1073](https://github.com/blink1073)) +- Remove outdated note on ipywidgets [#9707](https://github.com/jupyterlab/jupyterlab/pull/9707) ([@krassowski](https://github.com/krassowski)) +- 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 + +([GitHub contributors page for this release](https://github.com/jupyterlab/jupyterlab/graphs/contributors?from=2021-01-28&to=2021-07-27&type=c)) + +[@0618](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3A0618+updated%3A2021-01-28..2021-07-27&type=Issues) | [@achandak123](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aachandak123+updated%3A2021-01-28..2021-07-27&type=Issues) | [@afonit](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafonit+updated%3A2021-01-28..2021-07-27&type=Issues) | [@afshin](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aafshin+updated%3A2021-01-28..2021-07-27&type=Issues) | [@AgoCan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AAgoCan+updated%3A2021-01-28..2021-07-27&type=Issues) | [@agoose77](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aagoose77+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ainzzorl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aainzzorl+updated%3A2021-01-28..2021-07-27&type=Issues) | [@aiqc](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aaiqc+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ajbozarth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aajbozarth+updated%3A2021-01-28..2021-07-27&type=Issues) | [@akx](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aakx+updated%3A2021-01-28..2021-07-27&type=Issues) | [@andrewfulton9](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aandrewfulton9+updated%3A2021-01-28..2021-07-27&type=Issues) | [@Ashish-15s](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AAshish-15s+updated%3A2021-01-28..2021-07-27&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ablink1073+updated%3A2021-01-28..2021-07-27&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Abollwyvl+updated%3A2021-01-28..2021-07-27&type=Issues) | [@bsyouness](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Absyouness+updated%3A2021-01-28..2021-07-27&type=Issues) | [@cameron-toy](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Acameron-toy+updated%3A2021-01-28..2021-07-27&type=Issues) | [@consideRatio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AconsideRatio+updated%3A2021-01-28..2021-07-27&type=Issues) | [@darcsoel](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adarcsoel+updated%3A2021-01-28..2021-07-27&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adavidbrochart+updated%3A2021-01-28..2021-07-27&type=Issues) | [@dge8](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adge8+updated%3A2021-01-28..2021-07-27&type=Issues) | [@dharmaquark](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adharmaquark+updated%3A2021-01-28..2021-07-27&type=Issues) | [@dhirschfeld](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Adhirschfeld+updated%3A2021-01-28..2021-07-27&type=Issues) | [@DianeHu](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ADianeHu+updated%3A2021-01-28..2021-07-27&type=Issues) | [@dmonad](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Admonad+updated%3A2021-01-28..2021-07-27&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aecharles+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ellisonbg](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aellisonbg+updated%3A2021-01-28..2021-07-27&type=Issues) | [@fasiha](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afasiha+updated%3A2021-01-28..2021-07-27&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afcollonval+updated%3A2021-01-28..2021-07-27&type=Issues) | [@flying-sheep](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aflying-sheep+updated%3A2021-01-28..2021-07-27&type=Issues) | [@fperez](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Afperez+updated%3A2021-01-28..2021-07-27&type=Issues) | [@gereleth](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agereleth+updated%3A2021-01-28..2021-07-27&type=Issues) | [@goanpeca](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Agoanpeca+updated%3A2021-01-28..2021-07-27&type=Issues) | [@Guillaume-Garrigos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AGuillaume-Garrigos+updated%3A2021-01-28..2021-07-27&type=Issues) | [@hbcarlos](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ahbcarlos+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ian-r-rose](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aian-r-rose+updated%3A2021-01-28..2021-07-27&type=Issues) | [@isabela-pf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aisabela-pf+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jahn96](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajahn96+updated%3A2021-01-28..2021-07-27&type=Issues) | [@janjagusch](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajanjagusch+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jasongrout](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajasongrout+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jayqi](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajayqi+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jess-x](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajess-x+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jhamet93](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajhamet93+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jluttine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajluttine+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jochym](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajochym+updated%3A2021-01-28..2021-07-27&type=Issues) | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AJohanMabille+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajtpio+updated%3A2021-01-28..2021-07-27&type=Issues) | [@jupyterlab-dev-mode](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ajupyterlab-dev-mode+updated%3A2021-01-28..2021-07-27&type=Issues) | [@krassowska](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowska+updated%3A2021-01-28..2021-07-27&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Akrassowski+updated%3A2021-01-28..2021-07-27&type=Issues) | [@legendb317](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Alegendb317+updated%3A2021-01-28..2021-07-27&type=Issues) | [@loichuder](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aloichuder+updated%3A2021-01-28..2021-07-27&type=Issues) | [@maartenbreddels](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amaartenbreddels+updated%3A2021-01-28..2021-07-27&type=Issues) | [@manavendrasen](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amanavendrasen+updated%3A2021-01-28..2021-07-27&type=Issues) | [@manfromjupyter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amanfromjupyter+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mariobuikhuizen](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amariobuikhuizen+updated%3A2021-01-28..2021-07-27&type=Issues) | [@marthacryan](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amarthacryan+updated%3A2021-01-28..2021-07-27&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3AmartinRenou+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mbektas](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ambektas+updated%3A2021-01-28..2021-07-27&type=Issues) | [@meeseeksdev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksdev+updated%3A2021-01-28..2021-07-27&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ameeseeksmachine+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mellesies](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amellesies+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mgeier](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amgeier+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mlucool](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amlucool+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mnowacki-b](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amnowacki-b+updated%3A2021-01-28..2021-07-27&type=Issues) | [@mwakaba2](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Amwakaba2+updated%3A2021-01-28..2021-07-27&type=Issues) | [@NPetz](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ANPetz+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ognjenjevremovic](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aognjenjevremovic+updated%3A2021-01-28..2021-07-27&type=Issues) | [@ohrely](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aohrely+updated%3A2021-01-28..2021-07-27&type=Issues) | [@palewire](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apalewire+updated%3A2021-01-28..2021-07-27&type=Issues) | [@paravatha](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aparavatha+updated%3A2021-01-28..2021-07-27&type=Issues) | [@partev](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Apartev+updated%3A2021-01-28..2021-07-27&type=Issues) | [@plan-do-break-fix](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Aplan-do-break-fix+updated%3A2021-01-28..2021-07-27&type=Issues) | [@robertpyke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Arobertpyke+updated%3A2021-01-28..2021-07-27&type=Issues) | [@RodyLipson](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ARodyLipson+updated%3A2021-01-28..2021-07-27&type=Issues) | [@sarahspak](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asarahspak+updated%3A2021-01-28..2021-07-27&type=Issues) | [@saulshanabrook](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asaulshanabrook+updated%3A2021-01-28..2021-07-27&type=Issues) | [@shngt](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ashngt+updated%3A2021-01-28..2021-07-27&type=Issues) | [@skyetim](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Askyetim+updated%3A2021-01-28..2021-07-27&type=Issues) | [@smacke](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Asmacke+updated%3A2021-01-28..2021-07-27&type=Issues) | [@stadlerb](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Astadlerb+updated%3A2021-01-28..2021-07-27&type=Issues) | [@SylvainCorlay](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3ASylvainCorlay+updated%3A2021-01-28..2021-07-27&type=Issues) | [@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atelamonian+updated%3A2021-01-28..2021-07-27&type=Issues) | [@tonyfast](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atonyfast+updated%3A2021-01-28..2021-07-27&type=Issues) | [@trallard](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Atrallard+updated%3A2021-01-28..2021-07-27&type=Issues) | [@vidartf](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avidartf+updated%3A2021-01-28..2021-07-27&type=Issues) | [@vkaidalov-rft](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Avkaidalov-rft+updated%3A2021-01-28..2021-07-27&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Awelcome+updated%3A2021-01-28..2021-07-27&type=Issues) | [@yasmin-bb](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayasmin-bb+updated%3A2021-01-28..2021-07-27&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab+involves%3Ayuvipanda+updated%3A2021-01-28..2021-07-27&type=Issues) + +## v3.0 + +See the [JupyterLab +3.0](https://github.com/jupyterlab/jupyterlab/milestone/48?closed=1) +milestone on GitHub for the full list of pull requests and issues +closed. + +### v3.0.16 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.15...2badf555436063962451599a81b38b80f601a589)) + +### 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)) + +### v3.0.15 + +([Full Changelog](https://github.com/jupyterlab/jupyterlab/compare/v3.0.14...e1cda8e2fb69a6a01ec261ce13413acd306df4cb)) + +### 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 + +- [3.0.x] Remove Dependency on Jupyter Packaging [#10218](https://github.com/jupyterlab/jupyterlab/pull/10218) ([@jtpio](https://github.com/jtpio)) + +### 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 + +- 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) +- Update to `url-parse~=1.5.1` [#10219](https://github.com/jupyterlab/jupyterlab/pull/10219) [@jtpio](https://github.com/jtpio) +- Update packaging commands in the extension tutorial [#10104](https://github.com/jupyterlab/jupyterlab/pull/10104) [@jtpio](https://github.com/jtpio) +- Mention mamba as a means to install JupyterLab [#10093](https://github.com/jupyterlab/jupyterlab/pull/10093) [@SylvainCorlay](https://github.com/SylvainCorlay) + +### v3.0.14 + +- Clean up browser check [#10080](https://github.com/jupyterlab/jupyterlab/pull/10080) +- Loosen pin on jupyter-packaging [#9998](https://github.com/jupyterlab/jupyterlab/pull/9998) + +### v3.0.13 + +- Add cell id per notebook format 4.5 ([#10018](https://github.com/jupyterlab/jupyterlab/pull/10018)) +- Fix label for "Create Console for Editor" ([#9794](https://github.com/jupyterlab/jupyterlab/pull/9794)) +- Use blobs to set the svg source of an image in the image viewer ([#10029](https://github.com/jupyterlab/jupyterlab/pull/10029)) +- \[Fix\] Copy shareable link command ([#10021](https://github.com/jupyterlab/jupyterlab/pull/10021)) +- Clarify where the overrides.json file should be in the docs ([#9996](https://github.com/jupyterlab/jupyterlab/pull/9996)) +- Do not make unnecessary npm registry requests ([#9974](https://github.com/jupyterlab/jupyterlab/pull/9974)) +- Fix escaping of urls and paths ([#9978](https://github.com/jupyterlab/jupyterlab/pull/9978)) + +### v3.0.12 + +- Fix support for Safari by changing regular expression for Table of Contents ([#9962](https://github.com/jupyterlab/jupyterlab/pull/9962)) +- Fix DocRegistry FileType pattern matching ([#9958](https://github.com/jupyterlab/jupyterlab/pull/9958)) + +### v3.0.11 + +- Fix: use process/browser module as real polyfill ([#9636](https://github.com/jupyterlab/jupyterlab/pull/9636)) +- Fix Table of Contents extension markdown bug for HTML comments ([#9938](https://github.com/jupyterlab/jupyterlab/pull/9938)) +- Make Table of Contents extension not rewrite all notebook headers ([#9932](https://github.com/jupyterlab/jupyterlab/pull/9932)) + +### v3.0.10 + +- Fix watch mode for external extensions + ([#9915](https://github.com/jupyterlab/jupyterlab/pull/9915)) +- Bug fix for extension watch mode behavior + ([#9889](https://github.com/jupyterlab/jupyterlab/pull/9889), + [#9861](https://github.com/jupyterlab/jupyterlab/issues/9861)) + +### v3.0.9 + +- Remove the previous `file_to_run` logic. + ([#9848](https://github.com/jupyterlab/jupyterlab/pull/9848)) +- Enable Caching in Production Minimized Mode. + ([#9834](https://github.com/jupyterlab/jupyterlab/pull/9834)) +- Remove the auto-switch to “mobile” mode, and behavior switches associated + with mobile mode. + ([#9832](https://github.com/jupyterlab/jupyterlab/pull/9832)) +- Fix the display of breakpoints on restore. + ([#9828](https://github.com/jupyterlab/jupyterlab/pull/9828)) +- Update CI script timeouts. + ([#9825](https://github.com/jupyterlab/jupyterlab/pull/9825)) +- Fix mimerender test example and test in CI. + ([#9820](https://github.com/jupyterlab/jupyterlab/pull/9820)) + +### v3.0.8 + +- `@jupyterlab/rendermime`: upgraded `marked` dep past + vulnerability. + ([#9809](https://github.com/jupyterlab/jupyterlab/pull/9809)) +- Fix Services Tests. + ([#9806](https://github.com/jupyterlab/jupyterlab/pull/9806)) +- Enable jupyter labextension build/watch to work for custom + jupyterlab distributions. + ([#9697](https://github.com/jupyterlab/jupyterlab/pull/9697)) +- Add hash to webpack requests to enable caching. + ([#9776](https://github.com/jupyterlab/jupyterlab/pull/9776)) +- Update MANIFEST.in to include package_data files. + ([#9780](https://github.com/jupyterlab/jupyterlab/pull/9780)) +- Correct synchronization of tags between metadata and tags widget. + ([#9773](https://github.com/jupyterlab/jupyterlab/pull/9773)) +- Fix use of hyphen in module name. + ([#9655](https://github.com/jupyterlab/jupyterlab/pull/9655)) +- Add missing default_url fields to examples. + ([#9731](https://github.com/jupyterlab/jupyterlab/pull/9731), + [#9737](https://github.com/jupyterlab/jupyterlab/pull/9737)) + +### v3.0.7 + +- Add link for prebuilt extensions too. + ([#9702](https://github.com/jupyterlab/jupyterlab/pull/9702)) +- Remove outdated note on ipywidgets. + ([#9707](https://github.com/jupyterlab/jupyterlab/pull/9707)) +- Fix debug flag handling in build command. + ([#9715](https://github.com/jupyterlab/jupyterlab/pull/9715)) +- Update notebook toolbar example docs. + ([#9705](https://github.com/jupyterlab/jupyterlab/pull/9705)) +- Use `Path.resolve()` to get canonical case-sensitive path names. + ([#9709](https://github.com/jupyterlab/jupyterlab/pull/9709)) + +### v3.0.6 + +- Listen for `'restarting'` instead of `'autorestarting'` from server. + ([#9674](https://github.com/jupyterlab/jupyterlab/pull/9674)) +- Use `jupyterhub make_singleuser_app` mixin when available. + ([#9681](https://github.com/jupyterlab/jupyterlab/pull/9681)) +- Remove jest version constrain. + ([#9632](https://github.com/jupyterlab/jupyterlab/pull/9632)) +- Disable large uploads for notebook server \< 5.1. + ([#9628](https://github.com/jupyterlab/jupyterlab/pull/9628)) +- Ignore timeout errors when preloading settings. + ([#9629](https://github.com/jupyterlab/jupyterlab/pull/9629)) +- Customize template branch when upgrading extension. + ([#9630](https://github.com/jupyterlab/jupyterlab/pull/9630)) +- Renamed variable that clashed with a module. + ([#9641](https://github.com/jupyterlab/jupyterlab/pull/9641)) +- Allow for lazily retrieved documentation (with a getter). + ([#9643](https://github.com/jupyterlab/jupyterlab/pull/9643)) +- Upgrade `html-webpack-plugin` to support webpack 5. + ([#9651](https://github.com/jupyterlab/jupyterlab/pull/9651)) +- Fix viewing of PDF files in Safari. + ([#9656](https://github.com/jupyterlab/jupyterlab/pull/9656)) +- Add ToC entries for all headers in markdown cells. + ([#9358](https://github.com/jupyterlab/jupyterlab/pull/9358)) +- Revert creating a new browser tab for a new launcher when in simple + interface. + ([#9664](https://github.com/jupyterlab/jupyterlab/pull/9664)) +- Add `xeus-robot` to the debugger documentation. + ([#9661](https://github.com/jupyterlab/jupyterlab/pull/9661)) + +### v3.0.5 + +- Enable large file uploads. + ([#9616](https://github.com/jupyterlab/jupyterlab/pull/9616)) +- Fix display of `??` help on Windows. + ([#9617](https://github.com/jupyterlab/jupyterlab/pull/9617)) +- Update app and federated examples. + ([#9586](https://github.com/jupyterlab/jupyterlab/pull/9586)) + +### v3.0.4 + +- Do not use `??` in plain js, as it is too new. + ([#9606](https://github.com/jupyterlab/jupyterlab/pull/9606)) +- Fix handling of multiple notebooks for the debugger. + ([#9598](https://github.com/jupyterlab/jupyterlab/pull/9598)) +- Refactor labhub + CI. + ([#9604](https://github.com/jupyterlab/jupyterlab/pull/9604)) + +### v3.0.3 + +- Move open_browser to the top level configs of classes. + ([#9580](https://github.com/jupyterlab/jupyterlab/pull/9580)) + +### v3.0.2 + +- Manage kernel message queueing better to prevent out-of-order + execution. + ([#9571](https://github.com/jupyterlab/jupyterlab/pull/9571)) +- Fix breadcrumb links. + ([#9572](https://github.com/jupyterlab/jupyterlab/pull/9572)) +- Fix integration with JupyterHub. + ([#9568](https://github.com/jupyterlab/jupyterlab/pull/9568)) +- Fix parsing of empty CSV files. + ([#9557](https://github.com/jupyterlab/jupyterlab/pull/9557)) +- Use tree/table buttons to display debugger variables view mode. + ([#9502](https://github.com/jupyterlab/jupyterlab/pull/9502)) +- Update tutorial for final jlab 3 release. + ([#9562](https://github.com/jupyterlab/jupyterlab/pull/9562)) +- Fix upgrade_extension.py. + ([#9551](https://github.com/jupyterlab/jupyterlab/pull/9551), + [#9550](https://github.com/jupyterlab/jupyterlab/pull/9550)) +- Update the Binder link in the README to point to a 3.0 Binder. + ([#9549](https://github.com/jupyterlab/jupyterlab/pull/9549)) + +### v3.0.1 + +- Fixes error when applying `jupyterlab.upgrade_extension` on Windows. + ([#9546](https://github.com/jupyterlab/jupyterlab/pull/9509)) +- Improve upgrade script to add style settings. + ([#9515](https://github.com/jupyterlab/jupyterlab/pull/9515)) +- Fixed incorrect link to GitHub milestone. + ([#9516](https://github.com/jupyterlab/jupyterlab/pull/9516)) +- Split contribution guidelines into web-based and local instructions. + ([#9540](https://github.com/jupyterlab/jupyterlab/pull/9540)) +- Remove `--checkout 3.0` in the extension tutorial. + ([#9545](https://github.com/jupyterlab/jupyterlab/pull/9545)) +- Docs updates for 3.0. + ([#9546](https://github.com/jupyterlab/jupyterlab/pull/9546)) +- Fix usage test. + ([#9547](https://github.com/jupyterlab/jupyterlab/pull/9547)) +- Remove visible 1px border for terminal. + ([#9548](https://github.com/jupyterlab/jupyterlab/pull/9548)) + +### v3.0.0 + +### User-facing changes + +#### 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 +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/latest/user/extensions.html#extensions) +for more details. + +#### 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/latest/user/language.html) +for more details. + +#### 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/latest/user/debugger.html) +for more details. + +#### 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 + +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 +and other documents. + +#### Visual filter in file browser + +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 + +The default interface for JupyterLab now has system-wide sidebar panes +on the left side and sidebar panels that interact with a specific +document (such as the debugger or notebook property inspector) on the +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 + +The command palette is now a floating window that appears on top of your +JupyterLab workspace. This enables users to quickly invoke a command +while keeping the sidebar closed or switching sidebar panels. The +command palette can be put back into the sidebar by adjusting the +default in Advanced Settings. + +#### Jupyter Server + +JupyterLab 3.0 now depends on [Jupyter +Server](https://jupyter-server.readthedocs.io), which is a new Jupyter +project based on the server portion of the classic Notebook server. See +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 + +#### Prebuilt Extensions + +Users will typically consume prebuilt extensions, which are Python +packages with static assets built using `JupyterLab`. See the updated +APOD tutorial for the workflow of creating a prebuilt extension from +scratch. For existing extensions, there is a new +`python -m jupyterlab.upgrade_extension` script that can be used to +upgrade extensions. The script will update the relevant dependencies and +add the boilerplate to create the Python package. For extensions that +already contained Python packages (typically server extensions), the +files are not overwritten, and some manual copying of content is +required. See the +[example](https://github.com/jupyterlab/extension-examples/pull/119), +which used this script heavily. There are two highlighted commits that +demonstrate upgrading a server extension. Prebuilt extensions are also +known as federated extensions in the changes below, since they use the +federated module capability in Webpack 5. + +- Better handling of extensions that provide both prebuilt and source + extensions. + ([#9489](https://github.com/jupyterlab/jupyterlab/pull/9489), + [#9277](https://github.com/jupyterlab/jupyterlab/issues/9277)) +- Document new page config conventions + ([#9454](https://github.com/jupyterlab/jupyterlab/pull/9454), + [#9240](https://github.com/jupyterlab/jupyterlab/issues/9240)) +- Use stylemodule in prebuilt extensions + ([#9460](https://github.com/jupyterlab/jupyterlab/pull/9460), + [#9459](https://github.com/jupyterlab/jupyterlab/issues/9459)) +- Update style-loader and mini-css-extract-plugin + ([#9451](https://github.com/jupyterlab/jupyterlab/pull/9451)) +- Use a more explicit stylemodule key for js css imports + ([#9427](https://github.com/jupyterlab/jupyterlab/pull/9427), + [#9423](https://github.com/jupyterlab/jupyterlab/issues/9423)) +- Ignore source packages when building or loading jupyterlab if there + is a prebuilt package + ([#9424](https://github.com/jupyterlab/jupyterlab/pull/9424), + [#9277](https://github.com/jupyterlab/jupyterlab/issues/9277)) +- Include federated extensions in extension manager from the api + ([#9390](https://github.com/jupyterlab/jupyterlab/pull/9390), + [#9367](https://github.com/jupyterlab/jupyterlab/issues/9367)) +- Handle hyphens and switch to importlib in the develop script + ([#9471](https://github.com/jupyterlab/jupyterlab/pull/9471)) +- Chunk the jupyterlab and lumino modules together when building the + core application + ([#9359](https://github.com/jupyterlab/jupyterlab/pull/9359)) +- Link to the documentation in the extension manager federated dialog + ([#9327](https://github.com/jupyterlab/jupyterlab/pull/9327)) +- Federated extension script: change package name logic + ([#9326](https://github.com/jupyterlab/jupyterlab/pull/9326), + [#9320](https://github.com/jupyterlab/jupyterlab/issues/9320)) +- Do not error if requiredversion is not provided. + ([#9321](https://github.com/jupyterlab/jupyterlab/pull/9321)) +- Reinstate extension manager + ([#9317](https://github.com/jupyterlab/jupyterlab/pull/9317)) +- Built-in extensions using federated dependencies + ([#9310](https://github.com/jupyterlab/jupyterlab/pull/9310)) +- Update upgrade script to use labextension for outputdir + ([#9306](https://github.com/jupyterlab/jupyterlab/pull/9306)) +- Require \'package\' instead of \'package/\' so webpack activates + sharing + ([#9300](https://github.com/jupyterlab/jupyterlab/pull/9300)) +- Enable using federated extensions in dev mode when a flag is set. + ([#9286](https://github.com/jupyterlab/jupyterlab/pull/9286), + [#9235](https://github.com/jupyterlab/jupyterlab/issues/9235)) +- Update webpack to 5.3.1 + ([#9245](https://github.com/jupyterlab/jupyterlab/pull/9245)) +- Adds package installation info to labextension list and uninstall + output + ([#9244](https://github.com/jupyterlab/jupyterlab/pull/9244)) +- Restructure federated extensions to allow for package manager + metadata + ([#9239](https://github.com/jupyterlab/jupyterlab/pull/9239)) +- List the dynamic extensions in the extension manager + ([#9236](https://github.com/jupyterlab/jupyterlab/pull/9236), + [#8804](https://github.com/jupyterlab/jupyterlab/issues/8804)) +- Refuse to uninstall federated extensions. + ([#9232](https://github.com/jupyterlab/jupyterlab/pull/9232), + [#9230](https://github.com/jupyterlab/jupyterlab/issues/9230)) +- Allow custom webpack config for federated extensions + ([#9224](https://github.com/jupyterlab/jupyterlab/pull/9224), + [#9175](https://github.com/jupyterlab/jupyterlab/issues/9175)) +- Use the new webpack 5 'auto' publicpath + ([#9062](https://github.com/jupyterlab/jupyterlab/pull/9062), + [#9043](https://github.com/jupyterlab/jupyterlab/issues/9043)) +- Bump webpack to 5.0rc1 + ([#9091](https://github.com/jupyterlab/jupyterlab/pull/9091)) +- Update the upgrade script to not replace dev deps to caret + ([#9090](https://github.com/jupyterlab/jupyterlab/pull/9090)) +- Bump webpack to 5.0rc2 + ([#9103](https://github.com/jupyterlab/jupyterlab/pull/9103)) +- Fix watch mode + ([#9101](https://github.com/jupyterlab/jupyterlab/pull/9101), + [#9089](https://github.com/jupyterlab/jupyterlab/issues/9089)) +- Upgrade to webpack 5 + ([#9148](https://github.com/jupyterlab/jupyterlab/pull/9148)) +- Fix watch mode + ([#9146](https://github.com/jupyterlab/jupyterlab/pull/9146), + [#9116](https://github.com/jupyterlab/jupyterlab/issues/9116)) +- Docs: fix commands to watch + ([#9163](https://github.com/jupyterlab/jupyterlab/pull/9163)) +- Docs: update jupyter lab command in ext dev guide + ([#9165](https://github.com/jupyterlab/jupyterlab/pull/9165), + [#](https://github.com/jupyterlab/jupyterlab/pull/9163/issues/)) +- Update release test script to also install federated extensions + ([#9166](https://github.com/jupyterlab/jupyterlab/pull/9166), + [#8818](https://github.com/jupyterlab/jupyterlab/issues/8818)) +- Remove \@types/webpack (shipped with webpack 5) + ([#9167](https://github.com/jupyterlab/jupyterlab/pull/9167)) +- Mention jupyter-packaging and cookiecutter in migration guide + ([#9199](https://github.com/jupyterlab/jupyterlab/pull/9199)) +- Install jupyter_packaging in tutorial + ([#9190](https://github.com/jupyterlab/jupyterlab/pull/9190), + [#9174](https://github.com/jupyterlab/jupyterlab/issues/9174)) +- Handle sharing of linked packages and locally installed extensions + ([#9213](https://github.com/jupyterlab/jupyterlab/pull/9213), + [#9203](https://github.com/jupyterlab/jupyterlab/issues/9203)) +- Clean up federated extension install and upgrade + ([#8974](https://github.com/jupyterlab/jupyterlab/pull/8974)) +- Add `--development` and `--source-map` flags for building + extensions. + ([#8961](https://github.com/jupyterlab/jupyterlab/pull/8961), + [#8952](https://github.com/jupyterlab/jupyterlab/issues/8952)) +- Add extension upgrade script + ([#8950](https://github.com/jupyterlab/jupyterlab/pull/8950), + [#8870](https://github.com/jupyterlab/jupyterlab/issues/8870), + [#8869](https://github.com/jupyterlab/jupyterlab/issues/8869)) +- Improved handling of disabled extensions + ([#8944](https://github.com/jupyterlab/jupyterlab/pull/8944), + [#7481](https://github.com/jupyterlab/jupyterlab/issues/7481)) +- Add development mode to lab extension build scripts + ([#8918](https://github.com/jupyterlab/jupyterlab/pull/8918)) +- Pull federated extension loading data from the webpack compilation + ([#8913](https://github.com/jupyterlab/jupyterlab/pull/8913), + [#8842](https://github.com/jupyterlab/jupyterlab/issues/8842)) +- Update labextension build cli to include a parameter for setting the + webpack publicpath option + ([#8911](https://github.com/jupyterlab/jupyterlab/pull/8911)) +- Update apod extension tutorial + ([#8905](https://github.com/jupyterlab/jupyterlab/pull/8905), + [#8859](https://github.com/jupyterlab/jupyterlab/issues/8859)) +- Let webpack automatically determine the required version of + dependencies + ([#8875](https://github.com/jupyterlab/jupyterlab/pull/8875)) +- Fix rebuild of federated extension and add discovery metadata to + schema + ([#8874](https://github.com/jupyterlab/jupyterlab/pull/8874)) +- Fix build issues with publicpath + ([#8871](https://github.com/jupyterlab/jupyterlab/pull/8871)) +- Split buildutils into buildutils and builder + ([#8863](https://github.com/jupyterlab/jupyterlab/pull/8863), + [#8857](https://github.com/jupyterlab/jupyterlab/issues/8857)) +- Dynamically set public path in generated extensions according to + page config + ([#8861](https://github.com/jupyterlab/jupyterlab/pull/8861), + [#8827](https://github.com/jupyterlab/jupyterlab/issues/8827)) +- Clean up federated extension cli + ([#8855](https://github.com/jupyterlab/jupyterlab/pull/8855), + [#46](https://github.com/jupyterlab/jupyterlab-module-federation/issues/46)) +- Fix app example. + ([#8852](https://github.com/jupyterlab/jupyterlab/pull/8852)) +- Add lumino dependencies to buildutils so the phosphor webpack + aliasing works + ([#8850](https://github.com/jupyterlab/jupyterlab/pull/8850), + [#8822](https://github.com/jupyterlab/jupyterlab/issues/8822)) +- Add another federated example package. + ([#8847](https://github.com/jupyterlab/jupyterlab/pull/8847), + [#5](https://github.com/jupyterlab/jupyterlab-module-federation/issues/5)) +- Fixes for the federated example + ([#8846](https://github.com/jupyterlab/jupyterlab/pull/8846)) +- Add slash to publicpath + ([#8845](https://github.com/jupyterlab/jupyterlab/pull/8845)) +- Update watch plugin for webpack 5 + ([#8841](https://github.com/jupyterlab/jupyterlab/pull/8841), + [#8705](https://github.com/jupyterlab/jupyterlab/issues/8705)) +- Adding a mime extension to the webpack config + ([#8825](https://github.com/jupyterlab/jupyterlab/pull/8825)) +- Fix labextension build + ([#8821](https://github.com/jupyterlab/jupyterlab/pull/8821)) +- Fix boolean error + ([#8819](https://github.com/jupyterlab/jupyterlab/pull/8819)) +- CI and extension developer cleanup + ([#8810](https://github.com/jupyterlab/jupyterlab/pull/8810)) +- Adding extension to shared modules list + ([#8808](https://github.com/jupyterlab/jupyterlab/pull/8808)) +- Module federation implementation + ([#8802](https://github.com/jupyterlab/jupyterlab/pull/8802)) +- Fix examples and update webpack + ([#8779](https://github.com/jupyterlab/jupyterlab/pull/8779), + [#8767](https://github.com/jupyterlab/jupyterlab/issues/8767)) +- Add extension building scripts + ([#8772](https://github.com/jupyterlab/jupyterlab/pull/8772)) +- Keep the existing webpack file in staging + ([#8673](https://github.com/jupyterlab/jupyterlab/pull/8673)) +- Workaround for vega build error + ([#8666](https://github.com/jupyterlab/jupyterlab/pull/8666)) +- Add missing polyfill + ([#8664](https://github.com/jupyterlab/jupyterlab/pull/8664), + [#8660](https://github.com/jupyterlab/jupyterlab/issues/8660)) +- Add url as a polyfill dependency for apputils. + ([#8659](https://github.com/jupyterlab/jupyterlab/pull/8659), + [#8657](https://github.com/jupyterlab/jupyterlab/issues/8657)) +- Update to webpack 5b21 + ([#8651](https://github.com/jupyterlab/jupyterlab/pull/8651)) +- Fix examples and break into separate build + ([#8647](https://github.com/jupyterlab/jupyterlab/pull/8647), + [#8646](https://github.com/jupyterlab/jupyterlab/issues/8646)) +- Add cur extension for url-loader + ([#8634](https://github.com/jupyterlab/jupyterlab/pull/8634)) +- Experiment with module federation + ([#8385](https://github.com/jupyterlab/jupyterlab/pull/8385)) + +#### Jupyter Server + +JupyterLab 3.0 uses Jupyter Server instead of the classic Notebook +server. Existing server extensions will be shimmed, but it is advised to +update extensions to use +[jupyter_server](https://github.com/jupyter/jupyter_server). + +- Update server(s), nbclassic, pytest fixtures + ([#9478](https://github.com/jupyterlab/jupyterlab/pull/9478), + [#9473](https://github.com/jupyterlab/jupyterlab/issues/9473)) +- Add jupyter_core as a dependency + ([#9251](https://github.com/jupyterlab/jupyterlab/pull/9251)) +- Put exposeappinbrowser and quitbutton values back in page config + ([#9262](https://github.com/jupyterlab/jupyterlab/pull/9262)) +- Update favicon handling + ([#9145](https://github.com/jupyterlab/jupyterlab/pull/9145), + [#9138](https://github.com/jupyterlab/jupyterlab/issues/9138)) +- Enable JupyterLab to run as an old notebook server extension + ([#8956](https://github.com/jupyterlab/jupyterlab/pull/8956), + [#8943](https://github.com/jupyterlab/jupyterlab/issues/8943)) +- Fixed `static_url_prefix`, added classic notebook flags and aliases, + and bumped `jupyterlab_server` dependency + ([#8910](https://github.com/jupyterlab/jupyterlab/pull/8910)) +- Use favicons provided by `jupyter_server` + ([#8898](https://github.com/jupyterlab/jupyterlab/pull/8898), + [#8794](https://github.com/jupyterlab/jupyterlab/issues/8794)) +- Load `app_version` next to running on jupyter_server + ([#8889](https://github.com/jupyterlab/jupyterlab/pull/8889), + [#8812](https://github.com/jupyterlab/jupyterlab/issues/8812)) +- Reinstate the labhubapp + ([#8806](https://github.com/jupyterlab/jupyterlab/pull/8806), + [#8704](https://github.com/jupyterlab/jupyterlab/issues/8704)) +- Jupyterlab as server extension + ([#7416](https://github.com/jupyterlab/jupyterlab/pull/7416)) + +#### Internationalization + +The JupyterLab UI now supports translation. + +- Cleanup tsconfig for the translation extension + ([#9357](https://github.com/jupyterlab/jupyterlab/pull/9357)) +- Add options to add prefix to strings + ([#8946](https://github.com/jupyterlab/jupyterlab/pull/8946)) +- Add a standalone translation manager to be used outside of plugins + ([#8945](https://github.com/jupyterlab/jupyterlab/pull/8945)) +- Add missing string fixes + ([#8888](https://github.com/jupyterlab/jupyterlab/pull/8888)) +- Add crowdin badge + ([#8823](https://github.com/jupyterlab/jupyterlab/pull/8823)) +- Change `optionsmap` to a an array of tuples to be able to localize + the options + ([#8820](https://github.com/jupyterlab/jupyterlab/pull/8820)) +- Localize strings in jlab + ([#8800](https://github.com/jupyterlab/jupyterlab/pull/8800)) +- Add translation package + ([#8681](https://github.com/jupyterlab/jupyterlab/pull/8681)) + +#### Visual Debugger + +- Debugger-sidebar + ([#9452](https://github.com/jupyterlab/jupyterlab/pull/9452)) +- Handle multiple scopes in the debugger variables viewer + ([#9346](https://github.com/jupyterlab/jupyterlab/pull/9346)) +- Remove the ptvsd dependency from the debugger user docs + ([#9344](https://github.com/jupyterlab/jupyterlab/pull/9344)) +- Throws an error if the kernel cannot start the debugger + ([#9426](https://github.com/jupyterlab/jupyterlab/pull/9426)) +- Replace switch in debugger + ([#9432](https://github.com/jupyterlab/jupyterlab/pull/9432), + [#9354](https://github.com/jupyterlab/jupyterlab/issues/9354)) +- Sets terminatedebuggee to false + ([#9362](https://github.com/jupyterlab/jupyterlab/pull/9362)) +- Add missing return signatures in debugger sidebar + ([#9088](https://github.com/jupyterlab/jupyterlab/pull/9088)) +- Fix invisible breakpoint in debugger + ([#8908](https://github.com/jupyterlab/jupyterlab/pull/8908)) +- Port `jupyterlab/debugger` PR \#527 to JupyterLab + ([#8878](https://github.com/jupyterlab/jupyterlab/pull/8878)) +- Add jupyterlab debugger to core + ([#8747](https://github.com/jupyterlab/jupyterlab/pull/8747), + [#75](https://github.com/jupyterlab/team-compass/issues/75)) + +#### Table of Contents + +- Update toc ui + ([#9275](https://github.com/jupyterlab/jupyterlab/pull/9275)) +- Add tests for the toc + ([#8757](https://github.com/jupyterlab/jupyterlab/pull/8757), + [#8558](https://github.com/jupyterlab/jupyterlab/issues/8558)) +- Change toc to use labicon + ([#8692](https://github.com/jupyterlab/jupyterlab/pull/8692), + [#8557](https://github.com/jupyterlab/jupyterlab/issues/8557)) +- Switch from using settings registry to a signal for notebook + collapsing behavior in toc + ([#8601](https://github.com/jupyterlab/jupyterlab/pull/8601)) +- Remove `husky` dependencies from `toc` and `toc-extension` + ([#8571](https://github.com/jupyterlab/jupyterlab/pull/8571)) +- Merge toc extension into core + ([#8538](https://github.com/jupyterlab/jupyterlab/pull/8538)) + +#### Other + +- Resolve \'restarting\' state on reconnect + ([#9484](https://github.com/jupyterlab/jupyterlab/pull/9484), + [#9008](https://github.com/jupyterlab/jupyterlab/issues/9008)) +- Upgrade typedoc + ([#9483](https://github.com/jupyterlab/jupyterlab/pull/9483)) +- Update to typescript 4.1.3 + ([#9476](https://github.com/jupyterlab/jupyterlab/pull/9476)) +- Disable shut down all button if there is no running kernel or + terminal + ([#9468](https://github.com/jupyterlab/jupyterlab/pull/9468), + [#48](https://github.com/jtpio/jupyterlab-classic/issues/48)) +- Make some dependencies optional for the code console plugin + ([#9467](https://github.com/jupyterlab/jupyterlab/pull/9467)) +- Require tornado\>=6.1.0 + ([#9453](https://github.com/jupyterlab/jupyterlab/pull/9453)) +- Pin to tornado\>=6.1 on binder + ([#9449](https://github.com/jupyterlab/jupyterlab/pull/9449)) +- Fix some of the ui-components dependency warnings + ([#9448](https://github.com/jupyterlab/jupyterlab/pull/9448)) +- Fix browser test + ([#9447](https://github.com/jupyterlab/jupyterlab/pull/9447)) +- Support for lowercase search queries in the file browser + ([#9446](https://github.com/jupyterlab/jupyterlab/pull/9446)) +- Set the tabs menu title by default + ([#9445](https://github.com/jupyterlab/jupyterlab/pull/9445)) +- Add tests for interop between source and prebuilt extensions + ([#9443](https://github.com/jupyterlab/jupyterlab/pull/9443), + [#9333](https://github.com/jupyterlab/jupyterlab/issues/9333)) +- Make itreepathupdater optional in file browser plugin + ([#9442](https://github.com/jupyterlab/jupyterlab/pull/9442)) +- Make ilabshell optional in the filebrowser factory plugin + ([#9439](https://github.com/jupyterlab/jupyterlab/pull/9439)) +- Reduce yarn timeout + ([#9419](https://github.com/jupyterlab/jupyterlab/pull/9419)) +- Remove unused requires for the tree-resolver plugin + ([#9412](https://github.com/jupyterlab/jupyterlab/pull/9412)) +- Update \@types/react to \^17.0.0 + ([#9409](https://github.com/jupyterlab/jupyterlab/pull/9409)) +- Make css dependency graph of js modules + ([#9407](https://github.com/jupyterlab/jupyterlab/pull/9407)) +- Cleanup unused python imports in examples/ + ([#9404](https://github.com/jupyterlab/jupyterlab/pull/9404)) +- Clear the model and the signals upon continue response + ([#9402](https://github.com/jupyterlab/jupyterlab/pull/9402)) +- Fix scroll positions when clearing outputs + ([#9400](https://github.com/jupyterlab/jupyterlab/pull/9400), + [#9331](https://github.com/jupyterlab/jupyterlab/issues/9331)) +- Remove initial extra \_onmimetypechanged call + ([#9394](https://github.com/jupyterlab/jupyterlab/pull/9394)) +- Bump the eslint dev dependencies + ([#9391](https://github.com/jupyterlab/jupyterlab/pull/9391)) +- Reconnect to kernel on manual restart + ([#9388](https://github.com/jupyterlab/jupyterlab/pull/9388)) +- Remove the memory usage status bar item + ([#9386](https://github.com/jupyterlab/jupyterlab/pull/9386), + [#9363](https://github.com/jupyterlab/jupyterlab/issues/9363)) +- Change user references from single-document mode to simple interface + (mode) + ([#9380](https://github.com/jupyterlab/jupyterlab/pull/9380), + [#9378](https://github.com/jupyterlab/jupyterlab/issues/9378)) +- Reconnect to kernel on restart action + ([#9371](https://github.com/jupyterlab/jupyterlab/pull/9371)) +- Add a polyfill for path in the base webpack config + ([#9368](https://github.com/jupyterlab/jupyterlab/pull/9368), + [#9345](https://github.com/jupyterlab/jupyterlab/issues/9345)) +- Add reconnect to kernel main menu item, and notebook implementation. + ([#9356](https://github.com/jupyterlab/jupyterlab/pull/9356), + [#9353](https://github.com/jupyterlab/jupyterlab/issues/9353)) +- Update blueprint dependencies + ([#9350](https://github.com/jupyterlab/jupyterlab/pull/9350)) +- Target sys-prefix by default but allow you to specify user + ([#9347](https://github.com/jupyterlab/jupyterlab/pull/9347)) +- Eliminate eager sharing + ([#9348](https://github.com/jupyterlab/jupyterlab/pull/9348), + [#9343](https://github.com/jupyterlab/jupyterlab/issues/9343)) +- Revert opening in new tab in single-document mode + ([#9334](https://github.com/jupyterlab/jupyterlab/pull/9334), + [#9323](https://github.com/jupyterlab/jupyterlab/issues/9323)) +- Eager share only core packages and their dependencies + ([#9332](https://github.com/jupyterlab/jupyterlab/pull/9332), + [#9329](https://github.com/jupyterlab/jupyterlab/issues/9329)) +- Changed the expression to \"server unavailable or unreachable\" + instead of \"server not running\" + ([#9325](https://github.com/jupyterlab/jupyterlab/pull/9325)) +- Increase the pause between publishing and using npm packages to 5 + minutes + ([#9319](https://github.com/jupyterlab/jupyterlab/pull/9319)) +- Lint extension manager + ([#9318](https://github.com/jupyterlab/jupyterlab/pull/9318)) +- Refactor build conventions + ([#9312](https://github.com/jupyterlab/jupyterlab/pull/9312), + [#9304](https://github.com/jupyterlab/jupyterlab/issues/9304)) +- Make ilabshell optional for the launcher extension + ([#9305](https://github.com/jupyterlab/jupyterlab/pull/9305)) +- Update binder to use conda, which allows us to install our own + nodejs. + ([#9298](https://github.com/jupyterlab/jupyterlab/pull/9298)) +- Move the single document switch to the status bar + ([#9296](https://github.com/jupyterlab/jupyterlab/pull/9296)) +- Added utf-8 encoding parameter to create process + ([#9294](https://github.com/jupyterlab/jupyterlab/pull/9294), + [#8600](https://github.com/%5B/issues/8600)) +- Fix linting errors in github prs + ([#9293](https://github.com/jupyterlab/jupyterlab/pull/9293)) +- Enable mimedocument to use an optional specific renderer + ([#9291](https://github.com/jupyterlab/jupyterlab/pull/9291)) +- Pause after publishing packages to allow npm time to update their + listing + ([#9288](https://github.com/jupyterlab/jupyterlab/pull/9288)) +- Sidebar width + ([#9287](https://github.com/jupyterlab/jupyterlab/pull/9287), + [#8938](https://github.com/jupyterlab/jupyterlab/issues/8938)) +- Mybinder.org link for people who want to test their own branches in + the developer guidelines + ([#9284](https://github.com/jupyterlab/jupyterlab/pull/9284), + [#9255](https://github.com/jupyterlab/jupyterlab/issues/9255)) +- Remove ensure-max-old-space script + ([#9282](https://github.com/jupyterlab/jupyterlab/pull/9282)) +- Fix usage tests refusing to uninstall federated extensions + ([#9281](https://github.com/jupyterlab/jupyterlab/pull/9281), + [#9280](https://github.com/jupyterlab/jupyterlab/issues/9280)) +- Add a new menu shell area + ([#9274](https://github.com/jupyterlab/jupyterlab/pull/9274)) +- Fix \#9255 + ([#9273](https://github.com/jupyterlab/jupyterlab/pull/9273), + [#9255](https://github.com/jupyterlab/jupyterlab/issues/9255)) +- Fix theme path in jupyterlab builder + ([#9272](https://github.com/jupyterlab/jupyterlab/pull/9272)) +- Move document mode switch to separate plugin + ([#9270](https://github.com/jupyterlab/jupyterlab/pull/9270)) +- Fix styling of single-document mode switch in menu bar + ([#9267](https://github.com/jupyterlab/jupyterlab/pull/9267)) +- Make pdf viewer extension recognize pdf files + ([#9266](https://github.com/jupyterlab/jupyterlab/pull/9266)) +- Fix relative path handling in markdown images + ([#9264](https://github.com/jupyterlab/jupyterlab/pull/9264), + [#9253](https://github.com/jupyterlab/jupyterlab/issues/9253), + [#9243](https://github.com/jupyterlab/jupyterlab/issues/9243)) +- Add jupyterhub to page config + ([#9256](https://github.com/jupyterlab/jupyterlab/pull/9256), + [#9248](https://github.com/jupyterlab/jupyterlab/issues/9248)) +- Update to webpack-cli 4.1.0 + ([#9254](https://github.com/jupyterlab/jupyterlab/pull/9254)) +- Upgrade to react 17 + ([#9227](https://github.com/jupyterlab/jupyterlab/pull/9227)) +- Extension documentation + ([#9221](https://github.com/jupyterlab/jupyterlab/pull/9221)) +- Lint fixes + ([#9218](https://github.com/jupyterlab/jupyterlab/pull/9218)) +- Update change log + ([#9217](https://github.com/jupyterlab/jupyterlab/pull/9217)) +- Update committer list + ([#9215](https://github.com/jupyterlab/jupyterlab/pull/9215)) +- Upgrade to TypeScript 4 + ([#8883](https://github.com/jupyterlab/jupyterlab/pull/8883)) +- File browser filter + ([#8615](https://github.com/jupyterlab/jupyterlab/pull/8615)) +- Update yarn.lock. + ([#9095](https://github.com/jupyterlab/jupyterlab/pull/9095)) +- Handle notebook kernel in busy state on page reload + ([#9077](https://github.com/jupyterlab/jupyterlab/pull/9077)) +- Use span element to maintain ellipsis + ([#9075](https://github.com/jupyterlab/jupyterlab/pull/9075), + [#9074](https://github.com/jupyterlab/jupyterlab/issues/9074)) +- Add codemirror singleton plugin + ([#9067](https://github.com/jupyterlab/jupyterlab/pull/9067)) +- Support token authentication for terminal websocket communication + ([#9080](https://github.com/jupyterlab/jupyterlab/pull/9080)) +- Do not special-case logic for mainareawidget. + ([#9094](https://github.com/jupyterlab/jupyterlab/pull/9094)) +- Set an icon for the inspector main area widget + ([#9093](https://github.com/jupyterlab/jupyterlab/pull/9093)) +- Fix the open tabs handling of mainareawidget icons + ([#9092](https://github.com/jupyterlab/jupyterlab/pull/9092), + [#126](https://github.com/jupyterlab/extension-examples/issues/126)) +- Sort completion filtering results + ([#9098](https://github.com/jupyterlab/jupyterlab/pull/9098), + [#9048](https://github.com/jupyterlab/jupyterlab/issues/9048), + [#9048](https://github.com/jupyterlab/jupyterlab/issues/9048)) +- Add hover scrolling to menu, like toolbar. + ([#9097](https://github.com/jupyterlab/jupyterlab/pull/9097)) +- Add codemirror simple mode addon + ([#9123](https://github.com/jupyterlab/jupyterlab/pull/9123)) +- Create codeql-analysis.yml + ([#9119](https://github.com/jupyterlab/jupyterlab/pull/9119)) +- Create ensurevimkeymap function + ([#9161](https://github.com/jupyterlab/jupyterlab/pull/9161)) +- Increase size of docstring pop up tooltip + ([#9134](https://github.com/jupyterlab/jupyterlab/pull/9134), + [#9085](https://github.com/jupyterlab/jupyterlab/issues/9085)) +- Add a 2.x -\> 3.x migration guide + ([#9162](https://github.com/jupyterlab/jupyterlab/pull/9162), + [#9118](https://github.com/jupyterlab/jupyterlab/issues/9118)) +- Add an offline circle icon for disconnected or unknown kernel state + ([#9172](https://github.com/jupyterlab/jupyterlab/pull/9172)) +- Include js api in sphinx docs + ([#9179](https://github.com/jupyterlab/jupyterlab/pull/9179)) +- Update rtd build + ([#9182](https://github.com/jupyterlab/jupyterlab/pull/9182)) +- Allow to substitute the default completer renderer + ([#8930](https://github.com/jupyterlab/jupyterlab/pull/8930), + [#8926](https://github.com/jupyterlab/jupyterlab/issues/8926)) +- Update dependencies for beta + ([#8921](https://github.com/jupyterlab/jupyterlab/pull/8921)) +- Test cleanup + ([#8894](https://github.com/jupyterlab/jupyterlab/pull/8894)) +- Resize isolated iframes on content height change + ([#8909](https://github.com/jupyterlab/jupyterlab/pull/8909), + [#5696](https://github.com/jupyterlab/jupyterlab/issues/5696)) +- Update minimum python version to python 3.6. + ([#8903](https://github.com/jupyterlab/jupyterlab/pull/8903)) +- Update yarn.lock + ([#8862](https://github.com/jupyterlab/jupyterlab/pull/8862)) +- Makes some properties and methods of class dsvmodel accessible + outside the class. + ([#8849](https://github.com/jupyterlab/jupyterlab/pull/8849), + [#8848](https://github.com/jupyterlab/jupyterlab/issues/8848)) +- Do not use token parameters in websocket urls + ([#8835](https://github.com/jupyterlab/jupyterlab/pull/8835), + [#8813](https://github.com/jupyterlab/jupyterlab/issues/8813)) +- Use blocked/allowed extension naming in jupyterlab + ([#8799](https://github.com/jupyterlab/jupyterlab/pull/8799), + [#8533](https://github.com/jupyterlab/jupyterlab/issues/8533)) +- Create icon for pdfs in the filebrowser + ([#8791](https://github.com/jupyterlab/jupyterlab/pull/8791)) +- Correctly set base_url on workspace apps + ([#8788](https://github.com/jupyterlab/jupyterlab/pull/8788)) +- Pass in isessioncontextdialogs to notebookwidgetfactory + ([#8778](https://github.com/jupyterlab/jupyterlab/pull/8778)) +- Update encoding version in vega sample. + ([#8766](https://github.com/jupyterlab/jupyterlab/pull/8766)) +- Upgrade codemirror + ([#8739](https://github.com/jupyterlab/jupyterlab/pull/8739)) +- Rename the logconsole:nboutput plugin id + ([#8729](https://github.com/jupyterlab/jupyterlab/pull/8729)) +- Rename the celltags plugin id to \@jupyterlab/celltags + ([#8728](https://github.com/jupyterlab/jupyterlab/pull/8728)) +- Uncaught typeerror when switching kernels + ([#8727](https://github.com/jupyterlab/jupyterlab/pull/8727)) +- Change inspector detail_level to 1 + ([#8725](https://github.com/jupyterlab/jupyterlab/pull/8725)) +- Change main menu ranks to allow for application menu to l of file + ([#8719](https://github.com/jupyterlab/jupyterlab/pull/8719)) +- Handle errors in async browser_check + ([#8717](https://github.com/jupyterlab/jupyterlab/pull/8717), + [#8709](https://github.com/jupyterlab/jupyterlab/issues/8709)) +- Add mehmet and andrew to contributors, fix last name order + ([#8712](https://github.com/jupyterlab/jupyterlab/pull/8712)) +- Updated puppeteer version to v4.0.0 + ([#8707](https://github.com/jupyterlab/jupyterlab/pull/8707)) +- Update the singleton packages to include at least every package with + a \'tokens.ts\' file + ([#8703](https://github.com/jupyterlab/jupyterlab/pull/8703)) +- Update link to jupyter contributing guide + ([#8697](https://github.com/jupyterlab/jupyterlab/pull/8697), + [#8682](https://github.com/jupyterlab/jupyterlab/issues/8682)) +- Added ability to delete a document from titlebar context menu + ([#8670](https://github.com/jupyterlab/jupyterlab/pull/8670)) +- Move codemirror html tree and related css to shadow dom + ([#8584](https://github.com/jupyterlab/jupyterlab/pull/8584)) +- Support macoptionismeta option in terminal + ([#8573](https://github.com/jupyterlab/jupyterlab/pull/8573), + [#4236](https://github.com/jupyterlab/jupyterlab/issues/4236)) +- Align output baseline with prompt + ([#8561](https://github.com/jupyterlab/jupyterlab/pull/8561), + [#8560](https://github.com/jupyterlab/jupyterlab/issues/8560)) +- Use the same font-family for cell prompt and code + ([#8553](https://github.com/jupyterlab/jupyterlab/pull/8553), + [#8552](https://github.com/jupyterlab/jupyterlab/issues/8552)) +- Prompt to save files before rebuild + ([#8526](https://github.com/jupyterlab/jupyterlab/pull/8526), + [#7372](https://github.com/jupyterlab/jupyterlab/issues/7372)) +- Change json5 payload to json payload + ([#8225](https://github.com/jupyterlab/jupyterlab/pull/8225)) +- Move notebook logging plugin to notebook-extension package + ([#7830](https://github.com/jupyterlab/jupyterlab/pull/7830)) +- First pass at adding scroll to cell method + ([#6818](https://github.com/jupyterlab/jupyterlab/pull/6818)) +- 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 + +- Make the single document title widget work for widgets that are not + main area widgets + ([#9078](https://github.com/jupyterlab/jupyterlab/pull/9078)) +- Add border at top of single-document open menus + ([#9096](https://github.com/jupyterlab/jupyterlab/pull/9096), + [#9065](https://github.com/jupyterlab/jupyterlab/issues/9065)) +- Implement a simple checkbox for single-document mode in the menu + bar. ([#9100](https://github.com/jupyterlab/jupyterlab/pull/9100), + [#8292](https://github.com/jupyterlab/jupyterlab/issues/8292)) +- Followup \#9100: made sdm switch pretty, accessible + ([#9104](https://github.com/jupyterlab/jupyterlab/pull/9104)) +- Improved url scheme, state, interactions for single document mode + ([#8715](https://github.com/jupyterlab/jupyterlab/pull/8715)) +- Add workspace mime handler and loading/saving workspaces manually + ([#8691](https://github.com/jupyterlab/jupyterlab/pull/8691)) +- Modify ansi color fix + ([#8555](https://github.com/jupyterlab/jupyterlab/pull/8555), + [#8554](https://github.com/jupyterlab/jupyterlab/issues/8554)) +- Improve single document mode to address classic notebook usage cases + ([#8531](https://github.com/jupyterlab/jupyterlab/pull/8531)) +- Incrementally improve jupyterlab mobile ux + ([#8456](https://github.com/jupyterlab/jupyterlab/pull/8456)) + +#### Benchmarks (now a separate repository) + +- Move benchmarks to seperate repo + ([#8795](https://github.com/jupyterlab/jupyterlab/pull/8795)) +- Fix off by one error in benchmark samples + ([#8785](https://github.com/jupyterlab/jupyterlab/pull/8785)) +- Benchmark params configurable and increase timeout + ([#8786](https://github.com/jupyterlab/jupyterlab/pull/8786)) +- Benchmarks: new erroroutputs + larger timeout + notebook defs in + subfolder + ([#8783](https://github.com/jupyterlab/jupyterlab/pull/8783)) +- Add ability to compare benchmarks + ([#8737](https://github.com/jupyterlab/jupyterlab/pull/8737)) +- Benchmark notebook loads + ([#8020](https://github.com/jupyterlab/jupyterlab/pull/8020)) + +### Bugfixes + +- Fix lerna warning + ([#9061](https://github.com/jupyterlab/jupyterlab/pull/9061)) +- Fix doc build + ([#9063](https://github.com/jupyterlab/jupyterlab/pull/9063), + [#9060](https://github.com/jupyterlab/jupyterlab/issues/9060)) +- Make text settings menu work + ([#9066](https://github.com/jupyterlab/jupyterlab/pull/9066), + [#9042](https://github.com/jupyterlab/jupyterlab/issues/9042)) +- Fix lint check for the codemirror-extension package + ([#9087](https://github.com/jupyterlab/jupyterlab/pull/9087)) +- Fix the examples ci + ([#9150](https://github.com/jupyterlab/jupyterlab/pull/9150)) +- Test: cleanup eslint jest rules and files + ([#9125](https://github.com/jupyterlab/jupyterlab/pull/9125)) +- Switch to a different murmurhash2 implementation to handle unicode + characters + ([#9158](https://github.com/jupyterlab/jupyterlab/pull/9158)) +- Add more xxx to the mktemp command in release_test.sh + ([#9131](https://github.com/jupyterlab/jupyterlab/pull/9131)) +- Add setup.py and pyproject.toml to manifest.in + ([#9129](https://github.com/jupyterlab/jupyterlab/pull/9129)) +- Urlext.join cant handle colon in relative paths + ([#9169](https://github.com/jupyterlab/jupyterlab/pull/9169), + [#9159](https://github.com/jupyterlab/jupyterlab/issues/9159)) +- Remove absolute document search pane width + ([#9180](https://github.com/jupyterlab/jupyterlab/pull/9180), + [#9178](https://github.com/jupyterlab/jupyterlab/issues/9178)) +- Update session and kernel manager data only if there was a real + change. + ([#9189](https://github.com/jupyterlab/jupyterlab/pull/9189), + [#9133](https://github.com/jupyterlab/jupyterlab/issues/9133)) +- Update metadata recorded to align better with jupyter protocol + ([#9206](https://github.com/jupyterlab/jupyterlab/pull/9206)) +- Fix focus issues with command palette + ([#9210](https://github.com/jupyterlab/jupyterlab/pull/9210), + [#9121](https://github.com/jupyterlab/jupyterlab/issues/9121)) +- Update mimetype for dragging files + ([#8965](https://github.com/jupyterlab/jupyterlab/pull/8965), + [#8934](https://github.com/jupyterlab/jupyterlab/issues/8934)) +- Fix comment explaining the extension entry point. + ([#8964](https://github.com/jupyterlab/jupyterlab/pull/8964)) +- Security docs: link to jupyter-server instead of jupyter-noteboook + ([#8954](https://github.com/jupyterlab/jupyterlab/pull/8954)) +- Fix titles in the extension development docs + ([#8948](https://github.com/jupyterlab/jupyterlab/pull/8948)) +- Fix link syntax in the apod tutorial + ([#8942](https://github.com/jupyterlab/jupyterlab/pull/8942)) +- Fix codemirror text color issue with dark jupyter theme. + ([#8919](https://github.com/jupyterlab/jupyterlab/pull/8919), + [#8792](https://github.com/jupyterlab/jupyterlab/issues/8792)) +- Remove the extension path, not the entire extension directory, when + uninstalling an extension + ([#8904](https://github.com/jupyterlab/jupyterlab/pull/8904)) +- Header `'content-type'` should not be overwritten + ([#8891](https://github.com/jupyterlab/jupyterlab/pull/8891), + [#8890](https://github.com/jupyterlab/jupyterlab/issues/8890)) +- Make sure adding or removing a cell tag actually replaces the tag + list, so a changed signal is emitted for the cell metadata + ([#8751](https://github.com/jupyterlab/jupyterlab/pull/8751), + [#8534](https://github.com/jupyterlab/jupyterlab/issues/8534)) +- Fix up ensure package and repo + ([#8749](https://github.com/jupyterlab/jupyterlab/pull/8749), + [#8748](https://github.com/jupyterlab/jupyterlab/issues/8748)) +- Add comma in `extension_points.rst` to fix syntax error of code + ([#8745](https://github.com/jupyterlab/jupyterlab/pull/8745)) +- Fix: Contributing Guide Link is Out of Sync + ([#8665](https://github.com/jupyterlab/jupyterlab/pull/8665)) +- Fix api docs links + ([#8624](https://github.com/jupyterlab/jupyterlab/pull/8624), + [#8616](https://github.com/jupyterlab/jupyterlab/issues/8616)) +- Fix handling of disposed widgets after closing a panel in tutorial + ([#8623](https://github.com/jupyterlab/jupyterlab/pull/8623)) +- Fix small typos in docs for developing extensions + ([#8622](https://github.com/jupyterlab/jupyterlab/pull/8622)) +- Reload the application on manual state reset + ([#8621](https://github.com/jupyterlab/jupyterlab/pull/8621)) +- Remove superfluous page reload on workspace reset + ([#8619](https://github.com/jupyterlab/jupyterlab/pull/8619)) +- Remove superfluous console log from the application shell + ([#8618](https://github.com/jupyterlab/jupyterlab/pull/8618)) +- Fix minor typos in extension tutorial + ([#8613](https://github.com/jupyterlab/jupyterlab/pull/8613)) +- Fix minor typos in docs for extensions. + ([#8551](https://github.com/jupyterlab/jupyterlab/pull/8551)) +- Fix small typo in install docs + ([#8550](https://github.com/jupyterlab/jupyterlab/pull/8550)) +- Fix more linting errors + ([#8454](https://github.com/jupyterlab/jupyterlab/pull/8454)) +- 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.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) +milestone on GitHub for the full list of pull requests and issues +closed. + +### July 2020 + +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 + +- Cells can no longer be executed while kernels are terminating or + restarting. There is a new status for these events on the Kernel + Indicator + ([#8562](https://github.com/jupyterlab/jupyterlab/pull/8562), + [#8477](https://github.com/jupyterlab/jupyterlab/issues/8477)) + + + +- Adds a visual clue for distinguishing hidden files and folders in + the file browser window + ([#8393](https://github.com/jupyterlab/jupyterlab/pull/8393)) + + + +- Enable horizontal scrolling for toolbars to improve mobile + experience + ([#8417](https://github.com/jupyterlab/jupyterlab/pull/8417)) + + + +- Improves the right-click context menu for the file editor + ([#8425](https://github.com/jupyterlab/jupyterlab/pull/8425)) + + + +- Merge cell attachments when merging cells + ([#8427](https://github.com/jupyterlab/jupyterlab/pull/8427), + [#8414](https://github.com/jupyterlab/jupyterlab/issues/8414)) + + + +- Add styling for high memory usage warning in status bar with + nbresuse + ([#8437](https://github.com/jupyterlab/jupyterlab/pull/8437)) + + + +- Adds support for Python version 3.10 + ([#8445](https://github.com/jupyterlab/jupyterlab/pull/8445)) +- Support live editing of SVG with updating rendering + ([#8495](https://github.com/jupyterlab/jupyterlab/pull/8495), + [#8494](https://github.com/jupyterlab/jupyterlab/issues/8494)) + + + +### For developers + +- Specify that we recommend typescript over javascript for extensions + ([#8411](https://github.com/jupyterlab/jupyterlab/pull/8411)) +- Lazy load codemirror theme stylesheets. + ([#8506](https://github.com/jupyterlab/jupyterlab/pull/8506)) +- Increase the link expiry to one week + ([#8402](https://github.com/jupyterlab/jupyterlab/pull/8402)) +- Add documentation on private npm registry usage + ([#8455](https://github.com/jupyterlab/jupyterlab/pull/8455), + [#7827](https://github.com/jupyterlab/jupyterlab/issues/7827), + [#7660](https://github.com/jupyterlab/jupyterlab/issues/7660)) +- Add feature request template + slight reorg in readme + ([#8467](https://github.com/jupyterlab/jupyterlab/pull/8467)) +- Add link to react example in extension-examples repo + ([#8474](https://github.com/jupyterlab/jupyterlab/pull/8474)) +- Update documentation of whitelist/blacklist + ([#8540](https://github.com/jupyterlab/jupyterlab/pull/8540)) +- Improve whitelist figure description in documentation + ([#8517](https://github.com/jupyterlab/jupyterlab/pull/8517)) + +### Bugfixes + +- Typo: fix extensino to extension + ([#8512](https://github.com/jupyterlab/jupyterlab/pull/8512)) +- Close correct tab with close tab + ([#8529](https://github.com/jupyterlab/jupyterlab/pull/8529)) +- Remove unused css rules + ([#8547](https://github.com/jupyterlab/jupyterlab/pull/8547), + [#8537](https://github.com/jupyterlab/jupyterlab/issues/8537)) +- Fix small typo in getting started docs, proxy + ([#8549](https://github.com/jupyterlab/jupyterlab/pull/8549)) +- Fix link on CI badges + ([#8603](https://github.com/jupyterlab/jupyterlab/pull/8603)) +- Simplified multicursor backspace code + ([#8523](https://github.com/jupyterlab/jupyterlab/pull/8523)) +- Fix recent breaking changes to normalizepath in filebrowser + ([#8383](https://github.com/jupyterlab/jupyterlab/pull/8383), + [#8382](https://github.com/jupyterlab/jupyterlab/issues/8382)) +- Fix watch mode and add ci test + ([#8394](https://github.com/jupyterlab/jupyterlab/pull/8394)) +- Address CI failures + ([#8433](https://github.com/jupyterlab/jupyterlab/pull/8433)) +- Fix lint errors in dependency graph script + ([#8451](https://github.com/jupyterlab/jupyterlab/pull/8451)) +- Fix lint complaints coming up from github actions + ([#8452](https://github.com/jupyterlab/jupyterlab/pull/8452)) +- Address CI usage test timeout + ([#8464](https://github.com/jupyterlab/jupyterlab/pull/8464)) +- Add chokidar to dev_mode/package.json + ([#8481](https://github.com/jupyterlab/jupyterlab/pull/8481)) +- Fix autolink + ([#8496](https://github.com/jupyterlab/jupyterlab/pull/8496)) +- Update phosphor aliases + ([#8498](https://github.com/jupyterlab/jupyterlab/pull/8498)) +- Fix default return in Python when extension has no version metadata + ([#8430](https://github.com/jupyterlab/jupyterlab/pull/8430)) +- Updated the installation documentation on read the docs to match the + readme file on the repo + ([#8386](https://github.com/jupyterlab/jupyterlab/pull/8386)) +- Handle quit_button when launched as an extension + ([#8486](https://github.com/jupyterlab/jupyterlab/pull/8486), + [#8483](https://github.com/jupyterlab/jupyterlab/issues/8483)) +- Add worker-loader + ([#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.2 + +- Fix icon sidebar height for third party extensions + ([#8333](https://github.com/jupyterlab/jupyterlab/pull/8333)) +- Pin JupyterLab server requirement more tightly + ([#8330](https://github.com/jupyterlab/jupyterlab/pull/8330)) +- Scrolls cells into view after deletion + ([#8287](https://github.com/jupyterlab/jupyterlab/pull/8287)) +- Sets data attribute on file type in filebrowser + ([#8275](https://github.com/jupyterlab/jupyterlab/pull/8275)) + +### v2.1.1 + +- Pin puppeteer to fix ci + ([#8260](https://github.com/jupyterlab/jupyterlab/pull/8260)) +- 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) + +### 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 + +- Display the extension manager in the left sidebar by default. Users + will need to acknowledge the disclaimer in the extension manager + before using it. + ([#8050](https://github.com/jupyterlab/jupyterlab/pull/8050), + [#8145](https://github.com/jupyterlab/jupyterlab/pull/8145)) +- Added `blacklist and whitelist support ` for the + extension manager + ([#7989](https://github.com/jupyterlab/jupyterlab/pull/7989)) +- Automatically link URLs in notebook output text + ([#8075](https://github.com/jupyterlab/jupyterlab/pull/8075), + [#7393](https://github.com/jupyterlab/jupyterlab/issues/7393)) +- Added a \"Restart Kernel and Run All Cells...\" button to the + notebook toolbar + ([#8024](https://github.com/jupyterlab/jupyterlab/pull/8024)) + + + +- Added a context menu item for opening a Markdown editor from the + Markdown preview + ([#7942](https://github.com/jupyterlab/jupyterlab/pull/7942)) + +- Support Node.js 10+ + ([#8112](https://github.com/jupyterlab/jupyterlab/pull/8112), + [#8083](https://github.com/jupyterlab/jupyterlab/issues/8083)) + +- Added a command to replace the selection in an editor with text + (inserting if there is no selection). This can be assigned a + keyboard shortcut, as shown below. We also added a command to go + through a series of commands and run the first enabled command. + ([#7908](https://github.com/jupyterlab/jupyterlab/pull/7908)) Here + is a keyboard shortcut to insert text in a currently-active notebook + editor: + + ```js + { + command: "notebook:replace-selection", + selector: ".jp-Notebook", + keys: ["Ctrl L"], + args: {text: "lambda x: x"} + } + ``` + + Here is a keyboard shortcut to insert text into an editor of the + currently active console, file editor, or notebook: + + ```js + { + command: "apputils:run-first-enabled", + selector: "body", + keys: ["Ctrl L"], + args: { + commands: [ + "console:replace-selection", + "fileeditor:replace-selection", + "notebook:replace-selection", + ], + args: {text: "lambda x: x"} + } + } + ``` + +### For developers + +- `NotebookWidgetFactory` is now a plugin so it can be overridden + ([#8066](https://github.com/jupyterlab/jupyterlab/pull/8066), + [#7996](https://github.com/jupyterlab/jupyterlab/issues/7996)) +- Many improvements to `LabIcon`: work with all SVG loaders, improve + performance, fix issue with menus from extensions + ([#8125](https://github.com/jupyterlab/jupyterlab/pull/8125)) +- Change the header application area to a box panel, which means the + header area will display if its children set their minimum height + ([#8059](https://github.com/jupyterlab/jupyterlab/pull/8059), + [#7279](https://github.com/jupyterlab/jupyterlab/issues/7279)) +- JupyterLab\'s custom context menu is now disabled on all descendants + of a DOM element with a `data-jp-suppress-context-menu` attribute + ([#7877](https://github.com/jupyterlab/jupyterlab/pull/7877), + [#7670](https://github.com/jupyterlab/jupyterlab/issues/7670)) + +### Bugfixes + +- Fix property inspector restoration on reload + ([#8114](https://github.com/jupyterlab/jupyterlab/pull/8114)) +- Increase the timeout for yarn + ([#8104](https://github.com/jupyterlab/jupyterlab/pull/8104), + [#8102](https://github.com/jupyterlab/jupyterlab/issues/8102)) +- Fix find and replace with empty strings + ([#8100](https://github.com/jupyterlab/jupyterlab/pull/8100), + [#8098](https://github.com/jupyterlab/jupyterlab/issues/8098)) +- Select search text when focusing the search overlay + ([#8073](https://github.com/jupyterlab/jupyterlab/pull/8073), + [#7932](https://github.com/jupyterlab/jupyterlab/pull/7932)) +- Fix attaching images with spaces in their names to Markdown cells + ([#8095](https://github.com/jupyterlab/jupyterlab/pull/8095)) +- Fix build errors by distributing the `.yarnrc` configuration with + the Python package + ([#8045](https://github.com/jupyterlab/jupyterlab/pull/8045)) +- Throttle fetch requests in the setting registry\'s data connector + ([#7927](https://github.com/jupyterlab/jupyterlab/pull/7927)) +- Close the gap between lines in notebook output + ([#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) + +### April 2020 + +See the [JupyterLab +2.0.2](https://github.com/jupyterlab/jupyterlab/milestone/50?closed=1) +milestone on GitHub for the full list of pull requests and issues +closed. + +- Fix cell execution when recording timing + ([#8057](https://github.com/jupyterlab/jupyterlab/pull/8057), + [#8056](https://github.com/jupyterlab/jupyterlab/issues/8056)) +- Fix font settings for the editor + ([#8004](https://github.com/jupyterlab/jupyterlab/pull/8004), + [#7910](https://github.com/jupyterlab/jupyterlab/issues/7910)) +- Avoid redundant checkpoint calls on loading a notebook + ([#7926](https://github.com/jupyterlab/jupyterlab/pull/7926), + [#7889](https://github.com/jupyterlab/jupyterlab/issues/7889)) +- For developers: make kernel `IFuture.done` typings more correct by + not including `undefined` + ([#8032](https://github.com/jupyterlab/jupyterlab/pull/8032)) + +## [v2.0.0](https://github.com/jupyterlab/jupyterlab/releases) + +### 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 + +- 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 + ([#7673](https://github.com/jupyterlab/jupyterlab/pull/7673)) + +- `Shift Home` and `Shift End` shortcuts in a notebook select all + cells from the current cell to the top or bottom of a notebook, + respectively + ([#7177](https://github.com/jupyterlab/jupyterlab/pull/7177)) + +- Explicit \"No Kernel\" button in the kernel selection dialog for new + notebooks + ([#7647](https://github.com/jupyterlab/jupyterlab/pull/7647)) + +- Notebook `recordTiming` advanced setting to control whether + execution timing information is stored in notebook files + ([#7578](https://github.com/jupyterlab/jupyterlab/pull/7578)) + +- \"Select current running or last run cell\" command added (requires + notebook `recordTiming` advanced setting to be set to true) + ([#7551](https://github.com/jupyterlab/jupyterlab/pull/7551)) + +- Codemirror `lineWiseCopyCut` advanced setting to control the + behavior of the copy/cut keyboard shortcuts when there is no + selection + ([#7842](https://github.com/jupyterlab/jupyterlab/pull/7842)) + +- Refreshed the command palette and property inspector sidebar icons + and user interfaces + ([#7577](https://github.com/jupyterlab/jupyterlab/pull/7577), + [#7038](https://github.com/jupyterlab/jupyterlab/issues/7038), + [#7733](https://github.com/jupyterlab/jupyterlab/pull/7733), + [#7732](https://github.com/jupyterlab/jupyterlab/issues/7732), + [#7718](https://github.com/jupyterlab/jupyterlab/pull/7718), + [#7686](https://github.com/jupyterlab/jupyterlab/issues/7686)) + +- \"New File\" and \"New Markdown File\" items in file browser context + menu ([#7483](https://github.com/jupyterlab/jupyterlab/pull/7483), + [#4280](https://github.com/jupyterlab/jupyterlab/issues/4280)) + +- \"Download\" item in File menu + ([#7480](https://github.com/jupyterlab/jupyterlab/pull/7480)) + +- \"Restart Kernel and Run up to Selected Cell\" item in notebook + Kernel menu + ([#7789](https://github.com/jupyterlab/jupyterlab/pull/7789), + [#6746](https://github.com/jupyterlab/jupyterlab/issues/6746)) + +- In extension manager, the \"enable\" button is now only shown for + installed extensions + ([#7482](https://github.com/jupyterlab/jupyterlab/pull/7482)) + +- Dialogs can now be closed by clicking outside of them + ([#7885](https://github.com/jupyterlab/jupyterlab/pull/7885), + [#3784](https://github.com/jupyterlab/jupyterlab/issues/3784)) + +- `documentsearch:startWithReplace` command to open the document find + overlay with replace. There is not currently a default keyboard + shortcut for this, but one can be assigned as a custom keyboard + shortcut in Advanced Settings. + ([#7725](https://github.com/jupyterlab/jupyterlab/pull/7725)) + +- `#` added to the CSV Viewer delimiter options + ([#7367](https://github.com/jupyterlab/jupyterlab/pull/7367), + [#6324](https://github.com/jupyterlab/jupyterlab/issues/6324)) + +- The JSON viewer now only displays structure hints for arrays and + empty objects for a more streamlined feel + ([#7227](https://github.com/jupyterlab/jupyterlab/pull/7227)) + +- Optional platform-aware keyboard shortcut fields `linuxKeys`, + `macKeys`, and `winKeys` in keyboard shortcut definitions + ([#7589](https://github.com/jupyterlab/jupyterlab/pull/7589)) + + ```js + { + command: "application:toggle-mode", + selector: "body", + linuxKeys: ["Ctrl Shift M"], // only linux + macKeys: ["Cmd Shift Z"], // only mac + winKeys: ["Ctrl Shift B"], // only windows + keys: ["Accel Shift U"] // default shortcut + } + ``` + +- Added options for `jupyter lab clean` to clean specific parts of the + build, such as `--extensions`, `--settings`, `--static`, and `--all` + ([#7583](https://github.com/jupyterlab/jupyterlab/pull/7583), + [#6734](https://github.com/jupyterlab/jupyterlab/pull/6734)) + +- Removed the vega 4 and vega-lite 2 renderers (vega 5 and vega-lite 4 + is included in JupyterLab by default). These legacy renderers may be + available via custom extensions + ([#7650](https://github.com/jupyterlab/jupyterlab/pull/7650), + [#7523](https://github.com/jupyterlab/jupyterlab/issues/7523), + [#7658](https://github.com/jupyterlab/jupyterlab/pull/7658)) + +- JupyterHub users should use the `c.Spawner.default_url = '/lab'` + setting instead of the deprecated and now removed `labhubapp` + ([#7724](https://github.com/jupyterlab/jupyterlab/pull/7724)) + +### For developers + +See `extension_migration` for help in +migrating extensions to JupyterLab 2.0. + +#### Backward incompatible changes + +- Switch from `@phosphor` to `@lumino` dependencies. + ([#7582](https://github.com/jupyterlab/jupyterlab/pull/7582), + [#7534](https://github.com/jupyterlab/jupyterlab/issues/7534), + [#7763](https://github.com/jupyterlab/jupyterlab/pull/7763), + [#7762](https://github.com/jupyterlab/jupyterlab/issues/7762), + [#7595](https://github.com/jupyterlab/jupyterlab/pull/7595)) +- Factor out the `settingsregistry` and `statedb` packages from + coreutils + ([#7681](https://github.com/jupyterlab/jupyterlab/pull/7681), + [#7615](https://github.com/jupyterlab/jupyterlab/issues/7615)) +- Rework services architecture (sessions, kernels, terminals). Among + these changes, `ClientSession` is renamed to `SessionContext` and + the `IKernelConnection.connectToComm` method is replaced with + `IKernelConnection.createComm` and `IKernelConnection.hasComm` + methods. + ([#7252](https://github.com/jupyterlab/jupyterlab/pull/7252), + [#7674](https://github.com/jupyterlab/jupyterlab/pull/7674), + [#7820](https://github.com/jupyterlab/jupyterlab/pull/7820), + [#7694](https://github.com/jupyterlab/jupyterlab/pull/7694), + [#7690](https://github.com/jupyterlab/jupyterlab/issues/7690), + [#7682](https://github.com/jupyterlab/jupyterlab/pull/7682)) +- Upgrade to TypeScript 3.7 + ([#7522](https://github.com/jupyterlab/jupyterlab/pull/7522)) +- Remove `polling` from coreutils in favor for `@lumino/polling` + ([#7617](https://github.com/jupyterlab/jupyterlab/pull/7617)) +- TypeScript strict null checking in core packages + ([#7657](https://github.com/jupyterlab/jupyterlab/pull/7657), + [#7607](https://github.com/jupyterlab/jupyterlab/pull/7607)) +- Update state database list method to query based on namespace match. + ([#7742](https://github.com/jupyterlab/jupyterlab/pull/7742), + [#7257](https://github.com/jupyterlab/jupyterlab/issues/7257)) +- Address code todo items and deprecations for 2.0 + ([#7720](https://github.com/jupyterlab/jupyterlab/pull/7720), + [#7724](https://github.com/jupyterlab/jupyterlab/pull/7724)) +- Update Console panel tracker widgets + ([#7705](https://github.com/jupyterlab/jupyterlab/pull/7705), + [#7726](https://github.com/jupyterlab/jupyterlab/issues/7726), + [#7648](https://github.com/jupyterlab/jupyterlab/issues/7648), + [#7645](https://github.com/jupyterlab/jupyterlab/pull/7645)) +- Update contribution guide to require node v12+ + ([#7479](https://github.com/jupyterlab/jupyterlab/pull/7479)) +- New API for the `Running` sidebar extension + ([#6895](https://github.com/jupyterlab/jupyterlab/pull/6895), + [#6876](https://github.com/jupyterlab/jupyterlab/issues/6876)) +- Clean up handling of icons under unified LabIcon ( + [#7192](https://github.com/jupyterlab/jupyterlab/pull/7192) + [#7700](https://github.com/jupyterlab/jupyterlab/pull/7700), + [#7765](https://github.com/jupyterlab/jupyterlab/issues/7765), + [#7767](https://github.com/jupyterlab/jupyterlab/pull/7767), + [#7800](https://github.com/jupyterlab/jupyterlab/pull/7800), + [#7846](https://github.com/jupyterlab/jupyterlab/pull/7846), + [#7859](https://github.com/jupyterlab/jupyterlab/issues/7859), + [#7864](https://github.com/jupyterlab/jupyterlab/pull/7864), + [#7886](https://github.com/jupyterlab/jupyterlab/pull/7886)) + +#### Other changes + +- New property inspector used to display the properties of the + currently selected main area widget + ([#7665](https://github.com/jupyterlab/jupyterlab/pull/7665), + [#7664](https://github.com/jupyterlab/jupyterlab/issues/7664), + [#7718](https://github.com/jupyterlab/jupyterlab/pull/7718), + [#7686](https://github.com/jupyterlab/jupyterlab/issues/7686)) +- Allow metadata for launcher items + ([#7654](https://github.com/jupyterlab/jupyterlab/pull/7654), + [#7652](https://github.com/jupyterlab/jupyterlab/issues/7652)) +- Allow default file browser to restore manually. + ([#7695](https://github.com/jupyterlab/jupyterlab/pull/7695), + [#4009](https://github.com/jupyterlab/jupyterlab/issues/4009)) +- Upgrade bundled yarn to 1.21.1 + ([#7691](https://github.com/jupyterlab/jupyterlab/pull/7691), + [#7692](https://github.com/jupyterlab/jupyterlab/issues/7692)) +- Make session dialogs configurable + ([#7618](https://github.com/jupyterlab/jupyterlab/pull/7618), + [#7616](https://github.com/jupyterlab/jupyterlab/issues/7616)) +- Support transient editor configs + ([#7611](https://github.com/jupyterlab/jupyterlab/pull/7611), + [#7295](https://github.com/jupyterlab/jupyterlab/issues/7295)) +- Optionally force new browser tab + ([#7603](https://github.com/jupyterlab/jupyterlab/pull/7603), + [#7602](https://github.com/jupyterlab/jupyterlab/issues/7602)) +- Update core dependencies (e.g., `codemirror`, `xterm.js`, + `markdown`, `fontawesome`, etc.) + ([#7590](https://github.com/jupyterlab/jupyterlab/pull/7590), + [#7194](https://github.com/jupyterlab/jupyterlab/issues/7194), + [#7326](https://github.com/jupyterlab/jupyterlab/pull/7326), + [#6479](https://github.com/jupyterlab/jupyterlab/issues/6479), + [#7769](https://github.com/jupyterlab/jupyterlab/pull/7769)) +- Add storybook to `ui-components` + ([#7588](https://github.com/jupyterlab/jupyterlab/pull/7588), + [#6799](https://github.com/jupyterlab/jupyterlab/issues/6799)) +- Add explicit documentation encouraging people to re-use lab + components + ([#7543](https://github.com/jupyterlab/jupyterlab/pull/7543)) +- Enable TypeScript sourcemaps for debugging locally installed + labextensions + ([#7541](https://github.com/jupyterlab/jupyterlab/pull/7541)) +- Add `UseSignal` example to the docs + ([#7519](https://github.com/jupyterlab/jupyterlab/pull/7519)) +- Add `env` prop to kernel options + ([#7499](https://github.com/jupyterlab/jupyterlab/pull/7499)) +- Add kernelspec metadata + ([#7229](https://github.com/jupyterlab/jupyterlab/pull/7229), + [#7228](https://github.com/jupyterlab/jupyterlab/issues/7228)) +- Allow different mimetypes for the clipboard data + ([#7202](https://github.com/jupyterlab/jupyterlab/pull/7202)) +- Add password dialog to apputils + ([#7855](https://github.com/jupyterlab/jupyterlab/pull/7855)) +- Alias phosphor packages to lumino to allow a deprecation period for + phosphor + ([#7893](https://github.com/jupyterlab/jupyterlab/pull/7893)) +- Match react version in ui-components peerdependencies + ([#7794](https://github.com/jupyterlab/jupyterlab/pull/7794)) +- Fix lint-staged for both win and mac + ([#7784](https://github.com/jupyterlab/jupyterlab/pull/7784)) +- Update websocket workaround for node environments + ([#7780](https://github.com/jupyterlab/jupyterlab/pull/7780), + [#6934](https://github.com/jupyterlab/jupyterlab/pull/6934)) +- Fix handling of linked extensions + ([#7728](https://github.com/jupyterlab/jupyterlab/pull/7728), + [#6738](https://github.com/jupyterlab/jupyterlab/issues/6738)) +- Fix extension compatibility checks for prereleases and extensions + supporting multiple major versions of JupyterLab + ([#7723](https://github.com/jupyterlab/jupyterlab/pull/7723), + [#7241](https://github.com/jupyterlab/jupyterlab/issues/7241), + [#7919](https://github.com/jupyterlab/jupyterlab/pull/7919)) +- Teach update-dependency about more range specifiers and make it + adopt the current range for any tag + ([#7709](https://github.com/jupyterlab/jupyterlab/pull/7709)) +- Add support for giving a rank to items in the top area + ([#7278](https://github.com/jupyterlab/jupyterlab/pull/7278)) +- Apply all options to the initial JupyterLab application instance + ([#7251](https://github.com/jupyterlab/jupyterlab/pull/7251)) + +### Bugfixes + +- \"Copy Shareable Link\" in the file browser context menu now + properly works in JupyterHub + ([#7906](https://github.com/jupyterlab/jupyterlab/pull/7906)) +- Update Mathjax CDN in the cell and console examples + ([#7680](https://github.com/jupyterlab/jupyterlab/pull/7680)) +- Revert ensure-max-old-space now that Node 12+ has better default + memory ceilings + ([#7677](https://github.com/jupyterlab/jupyterlab/pull/7677), + [#7675](https://github.com/jupyterlab/jupyterlab/issues/7675)) +- Resolve race condition between default file browser and tree urls. + ([#7676](https://github.com/jupyterlab/jupyterlab/pull/7676), + [#4009](https://github.com/jupyterlab/jupyterlab/issues/4009)) +- Fix handling of code editor refresh + ([#7672](https://github.com/jupyterlab/jupyterlab/pull/7672), + [#7671](https://github.com/jupyterlab/jupyterlab/issues/7671)) +- Start new notebooks in edit mode + ([#7666](https://github.com/jupyterlab/jupyterlab/pull/7666), + [#6731](https://github.com/jupyterlab/jupyterlab/issues/6731)) +- Use consistent versions of React + ([#7661](https://github.com/jupyterlab/jupyterlab/pull/7661), + [#7655](https://github.com/jupyterlab/jupyterlab/issues/7655)) +- Add scrollbar styles to nbconvert-css + ([#7653](https://github.com/jupyterlab/jupyterlab/pull/7653)) +- Close output views when corresponding notebooks are closed + ([#7633](https://github.com/jupyterlab/jupyterlab/pull/7633), + [#7301](https://github.com/jupyterlab/jupyterlab/issues/7301)) +- Fixed incorrect white background for new command palette icon + ([#7609](https://github.com/jupyterlab/jupyterlab/pull/7609), + [#7577](https://github.com/jupyterlab/jupyterlab/issues/7577)) +- Block fetching the settings for a plugin that is disabled + ([#7147](https://github.com/jupyterlab/jupyterlab/pull/7147)) +- When timing metadata changes, ensure signal fires + ([#7576](https://github.com/jupyterlab/jupyterlab/pull/7576)) +- Prevent memory leaks in Vega renderer + ([#7564](https://github.com/jupyterlab/jupyterlab/pull/7564)) +- Handle cell execution cancellation when cell is disposed + ([#7555](https://github.com/jupyterlab/jupyterlab/pull/7555), + [#7554](https://github.com/jupyterlab/jupyterlab/issues/7554)) +- Fix dropdown option style issue on Windows + ([#7513](https://github.com/jupyterlab/jupyterlab/pull/7513)) +- Make sure label is linked to a control when checking for element + type ([#7458](https://github.com/jupyterlab/jupyterlab/pull/7458)) +- Refine log console message UX + ([#7448](https://github.com/jupyterlab/jupyterlab/pull/7448), + [#7444](https://github.com/jupyterlab/jupyterlab/issues/7444), + [#7443](https://github.com/jupyterlab/jupyterlab/issues/7443)) +- Fix multicursor backspacing + ([#7401](https://github.com/jupyterlab/jupyterlab/pull/7401), + [#7205](https://github.com/jupyterlab/jupyterlab/issues/7205)) +- Reset log display and count when non-notebook tab gets activated + ([#7334](https://github.com/jupyterlab/jupyterlab/pull/7334), + [#7325](https://github.com/jupyterlab/jupyterlab/issues/7325)) +- Fix Safari multiple tabs by working around a Safari bug. + ([#7316](https://github.com/jupyterlab/jupyterlab/pull/7316), + [#6921](https://github.com/jupyterlab/jupyterlab/issues/6921)) +- Skip custom click behavior on links when the download attribute is + set ([#7311](https://github.com/jupyterlab/jupyterlab/pull/7311), + [#5443](https://github.com/jupyterlab/jupyterlab/issues/5443)) +- Fix context menu hit test to deal with SVG nodes. + ([#7242](https://github.com/jupyterlab/jupyterlab/pull/7242), + [#7224](https://github.com/jupyterlab/jupyterlab/issues/7224)) +- Fix overwriting of target attribute of anchors rendered by + `IPython.display` + ([#7215](https://github.com/jupyterlab/jupyterlab/pull/7215), + [#6827](https://github.com/jupyterlab/jupyterlab/issues/6827)) +- Fix file browser location in tree view + ([#7155](https://github.com/jupyterlab/jupyterlab/pull/7155)) +- Stop too many fetch calls in docmanager-extension + ([#7879](https://github.com/jupyterlab/jupyterlab/pull/7879), + [#7874](https://github.com/jupyterlab/jupyterlab/pull/7874)) +- Ensures that `Shift Tab` dedent shortcut works correctly in the file + editor + ([#7865](https://github.com/jupyterlab/jupyterlab/pull/7865)) +- Fix unexpected jump to last search result when using documentsearch + ([#7835](https://github.com/jupyterlab/jupyterlab/pull/7835)) +- Fixed refresh issue for html viewer + ([#7824](https://github.com/jupyterlab/jupyterlab/pull/7824), + [#7552](https://github.com/jupyterlab/jupyterlab/pull/7552)) +- Fix for center-aligned images with IPython.display.image + ([#7798](https://github.com/jupyterlab/jupyterlab/pull/7798)) +- Changes to setting editor should trigger application dirty state + ([#7774](https://github.com/jupyterlab/jupyterlab/pull/7774), + [#7757](https://github.com/jupyterlab/jupyterlab/issues/7757)) +- Move vega from \"devdependencies\" to \"dependencies\" + ([#7699](https://github.com/jupyterlab/jupyterlab/pull/7699), + [#7689](https://github.com/jupyterlab/jupyterlab/issues/7689)) +- Restore default file browser manually. + ([#7695](https://github.com/jupyterlab/jupyterlab/pull/7695), + [#4009](https://github.com/jupyterlab/jupyterlab/issues/4009)) +- Use default `app_dir` when `app_dir` is `''` + ([#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) + +### 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 + +- Select cells from the current cell to the top of the notebook with + `Shift Home`, to the bottom of the notebook with `Shift End` + ([#7336](https://github.com/jupyterlab/jupyterlab/pull/7336), + [#6783](https://github.com/jupyterlab/jupyterlab/pull/6783)) +- Add a log console extension to display unhandled messages and other + activity + ([#7318](https://github.com/jupyterlab/jupyterlab/pull/7318), + [#7319](https://github.com/jupyterlab/jupyterlab/pull/7319), + [#7379](https://github.com/jupyterlab/jupyterlab/pull/7379), + [#7399](https://github.com/jupyterlab/jupyterlab/pull/7399), + [#7406](https://github.com/jupyterlab/jupyterlab/pull/7406), + [#7421](https://github.com/jupyterlab/jupyterlab/pull/7421)) +- Allow the npm `max-old-space` option to be specified outside of + JupyterLab + ([#7317](https://github.com/jupyterlab/jupyterlab/pull/7317)) +- Only display node structure in a JSON tree view for arrays and empty + objects + ([#7261](https://github.com/jupyterlab/jupyterlab/pull/7261)) +- Make much smaller distribution packages by not building JavaScript + source maps for releases. + ([#7150](https://github.com/jupyterlab/jupyterlab/pull/7150)) +- Add support for pasting cell attachments and dragging attachments + from the file browser + ([#5913](https://github.com/jupyterlab/jupyterlab/pull/5913), + [#5744](https://github.com/jupyterlab/jupyterlab/issues/5744)) +- Add a new `registry` configuration parameter to override the default + yarn repository when building + ([#7363](https://github.com/jupyterlab/jupyterlab/pull/7363), + [#7109](https://github.com/jupyterlab/jupyterlab/pull/7109), + [#7249](https://github.com/jupyterlab/jupyterlab/pull/7249), + [#7248](https://github.com/jupyterlab/jupyterlab/issues/7248)) + +### For developers + +- Update the Markdown renderer (`marked`) to 0.7.0 + ([#7328](https://github.com/jupyterlab/jupyterlab/pull/7328)) +- Remove datagrid as a singleton, allowing extensions to use newer + versions + ([#7312](https://github.com/jupyterlab/jupyterlab/pull/7312)) +- Add metadata to the kernelspec information + ([#7234](https://github.com/jupyterlab/jupyterlab/pull/7234)) +- Allow different mimetypes for the clipboard data + ([#7233](https://github.com/jupyterlab/jupyterlab/pull/7233)) +- Add inline svg icon support to toolbar buttons + ([#7232](https://github.com/jupyterlab/jupyterlab/pull/7232)) +- Add PageConfig functions to query if a plugin is deferred or + disabled + ([#7216](https://github.com/jupyterlab/jupyterlab/pull/7216)) +- Allow for renderers for nbformat.ierror to be created + ([#7203](https://github.com/jupyterlab/jupyterlab/pull/7203), + [#7193](https://github.com/jupyterlab/jupyterlab/issues/7193)) +- Refactor `fileeditor-extension` for modularization + ([#6904](https://github.com/jupyterlab/jupyterlab/pull/6904)) +- Add execution timing to cells + ([#6864](https://github.com/jupyterlab/jupyterlab/pull/6864), + [#3320](https://github.com/jupyterlab/jupyterlab/issues/3320)) + +### Bugfixes + +- Fix the `file-browser-path` query parameter + ([#7313](https://github.com/jupyterlab/jupyterlab/pull/7313)) +- Skip custom click behavior on links when the download attribute is + set ([#7323](https://github.com/jupyterlab/jupyterlab/pull/7323)) +- Fix opening multiple browser tabs in Safari + ([#7322](https://github.com/jupyterlab/jupyterlab/pull/7322)) +- Fix context menus on SVG icons + ([#7263](https://github.com/jupyterlab/jupyterlab/pull/7263)) +- Fix overwriting of target attribute of anchors rendered by + `IPython.display` + ([#7231](https://github.com/jupyterlab/jupyterlab/pull/7231)) +- Fix multi-cursor backspacing + ([#7205](https://github.com/jupyterlab/jupyterlab/pull/7205), + [#7401](https://github.com/jupyterlab/jupyterlab/pull/7401), + [#7413](https://github.com/jupyterlab/jupyterlab/pull/7413)) +- Fix mult-cursor cell splitting + ([#7207](https://github.com/jupyterlab/jupyterlab/pull/7207), + [#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) + +### 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 + +- `jupyter lab build` now has a `--minimize=False` option to build + without minimization to conserve memory and time + ([#6907](https://github.com/jupyterlab/jupyterlab/pull/6907)) +- Fix workspace reset functionality + ([#7106](https://github.com/jupyterlab/jupyterlab/pull/7106), + [#7105](https://github.com/jupyterlab/jupyterlab/issues/7105)) +- Restore behavior of the \"raises-exception\" cell tag + ([#7020](https://github.com/jupyterlab/jupyterlab/pull/7020), + [#7015](https://github.com/jupyterlab/jupyterlab/issues/7015)) +- Add settings to override theme font sizes + ([#6926](https://github.com/jupyterlab/jupyterlab/pull/6926)) +- Accept query parameter to optionally change file browser location + ([#6875](https://github.com/jupyterlab/jupyterlab/pull/6875)) +- Pressing escape in the console should switch out of edit mode + ([#6822](https://github.com/jupyterlab/jupyterlab/pull/6822)) +- Fix file browser downloads in Google Chrome + ([#6686](https://github.com/jupyterlab/jupyterlab/pull/6686)) +- Make it possible to override the default widgets to view a file + ([#6813](https://github.com/jupyterlab/jupyterlab/pull/6813), + [#4048](https://github.com/jupyterlab/jupyterlab/issues/4048)) +- Support installing multiple versions of the same extension + ([#6857](https://github.com/jupyterlab/jupyterlab/pull/6857)) +- Support JupyterHub server name for JupyterHub 1.0 + ([#6931](https://github.com/jupyterlab/jupyterlab/pull/6931)) +- Add docs to help users diagnose issues before creating them + ([#6971](https://github.com/jupyterlab/jupyterlab/pull/6971)) +- The JupyterLab conda-forge package is now a `noarch` + package. If you are using JupyterLab with `notebook` + version 5.2 or earlier, you may need to manually enable the + JupyterLab server extension. See the issue for more details + ([#7042](https://github.com/jupyterlab/jupyterlab/issues/7042)) + +### For developers + +- Expose install_kernel for tests so that outside projects can better + use the testing framework + ([#7089](https://github.com/jupyterlab/jupyterlab/pull/7089)) +- Fix `comm_info_request` content to conform to the Jupyter message + specification in a backwards-compatible way + ([#6949](https://github.com/jupyterlab/jupyterlab/pull/6949), + [#6947](https://github.com/jupyterlab/jupyterlab/issues/6947)) +- Add yarn package resolution to build to constrain core package + versions to patch semver ranges + ([#6938](https://github.com/jupyterlab/jupyterlab/pull/6938)) +- Make handling comm messages optional in a kernel connection. + ([#6929](https://github.com/jupyterlab/jupyterlab/pull/6929)) +- Expose icon svg to theme css + ([#6034](https://github.com/jupyterlab/jupyterlab/pull/6034), + [#7027](https://github.com/jupyterlab/jupyterlab/pull/7027)) +- Expose convenience functions for open dialogs + ([#6366](https://github.com/jupyterlab/jupyterlab/pull/6366), + [#6365](https://github.com/jupyterlab/jupyterlab/issues/6365)) +- Add debug messages to possible kernel messages + ([#6704](https://github.com/jupyterlab/jupyterlab/pull/6704)) +- Add server side coreconfig object + ([#6991](https://github.com/jupyterlab/jupyterlab/pull/6991)) + +### Bug fixes + +- Handle errors that occur during kernel selection + ([#7094](https://github.com/jupyterlab/jupyterlab/pull/7094)) +- Fix escaping issues for page config and other template variables + ([#7016](https://github.com/jupyterlab/jupyterlab/pull/7016), + [#7024](https://github.com/jupyterlab/jupyterlab/issues/7024), + [#7061](https://github.com/jupyterlab/jupyterlab/pull/7061), + [#7058](https://github.com/jupyterlab/jupyterlab/issues/7058), + [#6858](https://github.com/jupyterlab/jupyterlab/issues/6858)) +- Require jinja2 2.10+ to fix escaping issues + ([#7055](https://github.com/jupyterlab/jupyterlab/pull/7055), + [#7053](https://github.com/jupyterlab/jupyterlab/issues/7053)) +- Increase the search debounce from 100ms to 500ms to increase + incremental search responsiveness in large documents + ([#7034](https://github.com/jupyterlab/jupyterlab/pull/7034)) +- Fix vega downloads and download urls in general + ([#7022](https://github.com/jupyterlab/jupyterlab/pull/7022), + [#7017](https://github.com/jupyterlab/jupyterlab/issues/7017), + [#7098](https://github.com/jupyterlab/jupyterlab/pull/7098), + [#7047](https://github.com/jupyterlab/jupyterlab/issues/7047)) +- Do not complain in the build about duplicate or optional packages + ([#7013](https://github.com/jupyterlab/jupyterlab/pull/7013)) +- Fix contextual help layout for R help + ([#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) + +### June 28, 2019 + +See the [JupyterLab +1.0.0](https://github.com/jupyterlab/jupyterlab/milestone/2?closed=1) +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 + + + +We have added first class support for find and replace across +JupyterLab. It is currently supported in notebooks and text files and is +extensible for other widgets who wish to support it. +([#6350](https://github.com/jupyterlab/jupyterlab/pull/6350), +[#6322](https://github.com/jupyterlab/jupyterlab/issues/6322), +[#6301](https://github.com/jupyterlab/jupyterlab/pull/6301), +[#6282](https://github.com/jupyterlab/jupyterlab/pull/6282), +[#6256](https://github.com/jupyterlab/jupyterlab/pull/6256), +[#6241](https://github.com/jupyterlab/jupyterlab/pull/6241), +[#6237](https://github.com/jupyterlab/jupyterlab/pull/6237), +[#6159](https://github.com/jupyterlab/jupyterlab/pull/6159), +[#6081](https://github.com/jupyterlab/jupyterlab/issues/6081), +[#6155](https://github.com/jupyterlab/jupyterlab/pull/6155), +[#6094](https://github.com/jupyterlab/jupyterlab/pull/6094), +[#6024](https://github.com/jupyterlab/jupyterlab/pull/6024), +[#5937](https://github.com/jupyterlab/jupyterlab/pull/5937), +[#5795](https://github.com/jupyterlab/jupyterlab/pull/5795), +[#1074](https://github.com/jupyterlab/jupyterlab/issues/1074)) + +### Status Bar + + + +We have integrated the [JupyterLab Status Bar +package](https://github.com/jupyterlab/jupyterlab-statusbar) package +into the core distribution. Extensions can add their own status to it as +well ([#5577](https://github.com/jupyterlab/jupyterlab/pull/5577), +[#5525](https://github.com/jupyterlab/jupyterlab/pull/5525) +[#5990](https://github.com/jupyterlab/jupyterlab/pull/5990), +[#5982](https://github.com/jupyterlab/jupyterlab/issues/5982), +[#5514](https://github.com/jupyterlab/jupyterlab/pull/5514), +[#5508](https://github.com/jupyterlab/jupyterlab/pull/5508), +[#5352](https://github.com/jupyterlab/jupyterlab/issues/5352)). + +### JupyterHub Integration + +- We now include the JupyterHub extension in core JupyterLab, so you + no longer need to install `@jupyterlab/hub-extension`. + ([#6451](https://github.com/jupyterlab/jupyterlab/pull/6451), + [#6428](https://github.com/jupyterlab/jupyterlab/issues/6428)) +- JupyterLab now has a File \> Logout menu entry when running with + JupyterHub + ([#6087](https://github.com/jupyterlab/jupyterlab/pull/6087), + [#5966](https://github.com/jupyterlab/jupyterlab/issues/5966)) + +### 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 + +- The launcher displays longer kernel names and supports keyboard + navigation + ([#6587](https://github.com/jupyterlab/jupyterlab/pull/6587)) +- Notebook outputs without any valid MimeType renderers will not be + displayed, instead of displaying an error + ([#6559](https://github.com/jupyterlab/jupyterlab/pull/6559), + [#6216](https://github.com/jupyterlab/jupyterlab/issues/6216)) +- Add tooltip to file browser root breadcrumb icon showing the server + root, if it is available + ([#6552](https://github.com/jupyterlab/jupyterlab/pull/6552)) +- Downloading a file will no longer open a new browser window + ([#6546](https://github.com/jupyterlab/jupyterlab/pull/6546)) +- Rename the help \"Inspector\" to \"Contextual Help\" and move it to + the \"Help\" menu + ([#6493](https://github.com/jupyterlab/jupyterlab/pull/6493), + [#6488](https://github.com/jupyterlab/jupyterlab/issues/6488), + [#6678](https://github.com/jupyterlab/jupyterlab/pull/6678), + [#6671](https://github.com/jupyterlab/jupyterlab/pull/6671)) +- Update many of the icons to make them more consistent + ([#6672](https://github.com/jupyterlab/jupyterlab/pull/6672), + [#6618](https://github.com/jupyterlab/jupyterlab/issues/6618), + [#6664](https://github.com/jupyterlab/jupyterlab/pull/6664), + [#6621](https://github.com/jupyterlab/jupyterlab/issues/6621)) +- Update the settings UI to remove the table view + ([#6654](https://github.com/jupyterlab/jupyterlab/pull/6654), + [#6622](https://github.com/jupyterlab/jupyterlab/issues/6622), + [#6653](https://github.com/jupyterlab/jupyterlab/pull/6653), + [#6623](https://github.com/jupyterlab/jupyterlab/issues/6623), + [#6646](https://github.com/jupyterlab/jupyterlab/pull/6646), + [#6642](https://github.com/jupyterlab/jupyterlab/issues/6642)) +- Replace FAQ Extension with link to JupyterLab documentation + ([#6628](https://github.com/jupyterlab/jupyterlab/pull/6628), + [#6608](https://github.com/jupyterlab/jupyterlab/issues/6608), + [#6625](https://github.com/jupyterlab/jupyterlab/pull/6625), + [#6610](https://github.com/jupyterlab/jupyterlab/issues/6610)) +- Change the default keyboard shortcut for closing a tab to be `Alt+w` + instead of `Cmd/Ctrl+w` to avoid conflicts with operating systems. + ([#6486](https://github.com/jupyterlab/jupyterlab/pull/6486), + [#6357](https://github.com/jupyterlab/jupyterlab/issues/6357)) +- Show help text in Inspector window to describe you should select a + function + ([#6476](https://github.com/jupyterlab/jupyterlab/pull/6476)) +- Fixes SVG rendering + ([#6469](https://github.com/jupyterlab/jupyterlab/pull/6469), + [#6295](https://github.com/jupyterlab/jupyterlab/issues/6295)) +- Add support for dropping a tab in the tab bar area. + ([#6454](https://github.com/jupyterlab/jupyterlab/pull/6454), + [#5406](https://github.com/jupyterlab/jupyterlab/issues/5406)) +- Switch some default shortcuts to use `Accel` instead of `Ctrl` so + they are more natural for Mac users + ([#6447](https://github.com/jupyterlab/jupyterlab/pull/6447), + [#5023](https://github.com/jupyterlab/jupyterlab/issues/5023)) +- Add ability to tell between hover and selected command palette items + ([#6407](https://github.com/jupyterlab/jupyterlab/pull/6407), + [#279](https://github.com/jupyterlab/jupyterlab/issues/279)) +- Hide the \"Last Modified\" column when the file browser is narrow + ([#6406](https://github.com/jupyterlab/jupyterlab/pull/6406), + [#6093](https://github.com/jupyterlab/jupyterlab/issues/6093)) +- Support copy/paste in terminal and Mac OS using `Ctrl+C` and + `Ctrl+V` + ([#6391](https://github.com/jupyterlab/jupyterlab/pull/6391), + [#6385](https://github.com/jupyterlab/jupyterlab/issues/6385), + [#1146](https://github.com/jupyterlab/jupyterlab/issues/1146)) +- Support scrolling in running kernels panel + ([#6383](https://github.com/jupyterlab/jupyterlab/pull/6383), + [#6371](https://github.com/jupyterlab/jupyterlab/issues/6371)) +- Adds ability to \"Merge Selected Cells\" in the context menu in the + notebook + ([#6375](https://github.com/jupyterlab/jupyterlab/pull/6375), + [#6318](https://github.com/jupyterlab/jupyterlab/issues/6318)) +- Turn On Accessibility In Xterm.js to make it more compatible for + screen readers + ([#6359](https://github.com/jupyterlab/jupyterlab/pull/6359)) +- When selecting cells using the keyboard shortcuts, we now skip + collapsed cells + ([#6356](https://github.com/jupyterlab/jupyterlab/pull/6356), + [#3233](https://github.com/jupyterlab/jupyterlab/issues/3233)) +- Supporting opening `.geojson` files in JSON viewer + ([#6349](https://github.com/jupyterlab/jupyterlab/pull/6349)) +- Performance fixes for text-based progress bars + ([#6304](https://github.com/jupyterlab/jupyterlab/pull/6304), + [#4202](https://github.com/jupyterlab/jupyterlab/issues/4202)) +- Add support for rendering Vega 5 and Vega Lite 3 while keeping the + existing Vega 4 and Vega Lite 2 renderers + ([#6294](https://github.com/jupyterlab/jupyterlab/pull/6294), + [#6133](https://github.com/jupyterlab/jupyterlab/pull/6133), + [#6128](https://github.com/jupyterlab/jupyterlab/issues/6128), + [#6689](https://github.com/jupyterlab/jupyterlab/pull/6689), + [#6685](https://github.com/jupyterlab/jupyterlab/pull/6685), + [#6684](https://github.com/jupyterlab/jupyterlab/issues/6684), + [#6675](https://github.com/jupyterlab/jupyterlab/issues/6675), + [#6591](https://github.com/jupyterlab/jupyterlab/pull/6591), + [#6572](https://github.com/jupyterlab/jupyterlab/issues/6572)) +- Drag and drop console cells into a notebook or text editor + ([#5585](https://github.com/jupyterlab/jupyterlab/pull/5585), + [#4847](https://github.com/jupyterlab/jupyterlab/issues/4847)) +- Drag and drop notebook cells into a console or text editor + ([#5571](https://github.com/jupyterlab/jupyterlab/pull/5571), + [#3732](https://github.com/jupyterlab/jupyterlab/issues/3732)) +- The extension manager search now sorts extensions by the score + assigned to them by NPM instead of alphabetically + ([#5649](https://github.com/jupyterlab/jupyterlab/pull/5649)) +- Notify the user when a kernel is automatically restarted, for + example, if crashes from an out of memory error + ([#6246](https://github.com/jupyterlab/jupyterlab/pull/6246), + [#4273](https://github.com/jupyterlab/jupyterlab/issues/4273)) +- Expose the extension manager in a command and menu item + ([#6200](https://github.com/jupyterlab/jupyterlab/pull/6200)) +- Add command to render all Markdown cells + ([#6029](https://github.com/jupyterlab/jupyterlab/pull/6029), + [#6017](https://github.com/jupyterlab/jupyterlab/issues/6017)) +- Supports using shift to select text in output area + ([#6015](https://github.com/jupyterlab/jupyterlab/pull/6015), + [#4800](https://github.com/jupyterlab/jupyterlab/issues/4800)) +- Output areas that opened in new views are restored properly now on + reload + ([#5981](https://github.com/jupyterlab/jupyterlab/pull/5981), + [#5976](https://github.com/jupyterlab/jupyterlab/issues/5976)) +- Add support for managing notebook metadata under a new \"Advanced + Tools\" section in the cell tools area. The cell and notebook + metadata now always reflect the current state of the notebook + ([#5968](https://github.com/jupyterlab/jupyterlab/pull/5968), + [#5200](https://github.com/jupyterlab/jupyterlab/issues/5200)) +- Inherit terminal theme from core theme + ([#5964](https://github.com/jupyterlab/jupyterlab/pull/5964)) +- Adds a built-in HTML viewer so that you can view HTML files + ([#5962](https://github.com/jupyterlab/jupyterlab/pull/5962), + [#5855](https://github.com/jupyterlab/jupyterlab/pull/5855), + [#2369](https://github.com/jupyterlab/jupyterlab/issues/2369)) +- New workspaces are now automatically generated when you create a new + window with the same workspace name. + ([#5950](https://github.com/jupyterlab/jupyterlab/pull/5950), + [#5854](https://github.com/jupyterlab/jupyterlab/issues/5854), + [#5830](https://github.com/jupyterlab/jupyterlab/pull/5830), + [#5214](https://github.com/jupyterlab/jupyterlab/issues/5214)) +- We now add a hint to the context menu to describe how you can access + the native browser menu + ([#5940](https://github.com/jupyterlab/jupyterlab/pull/5940), + [#4023](https://github.com/jupyterlab/jupyterlab/issues/4023)) +- The tabs on the left panel have changed to make them more + understandable + ([#5920](https://github.com/jupyterlab/jupyterlab/pull/5920), + [#5269](https://github.com/jupyterlab/jupyterlab/issues/5269)) +- Start a new terminal when the page is refreshed and the old terminal + has died + ([#5917](https://github.com/jupyterlab/jupyterlab/pull/5917)) +- Add a command to open the main menus, which can be assigned to a + keyboard shortcut to open and navigate menus without a mouse + ([#5910](https://github.com/jupyterlab/jupyterlab/pull/5910), + [#3074](https://github.com/jupyterlab/jupyterlab/issues/3074)) +- The contextual help now updates based on changes in the cursor from + the mouse instead of just from the keyboard + ([#5906](https://github.com/jupyterlab/jupyterlab/pull/5906), + [#5899](https://github.com/jupyterlab/jupyterlab/issues/5899)) +- The launcher now updates when the kernels change on the server + ([#5904](https://github.com/jupyterlab/jupyterlab/pull/5904), + [#5676](https://github.com/jupyterlab/jupyterlab/issues/5676)) +- Retain cell auto scroll behavior even when a cell output is cleared + ([#5817](https://github.com/jupyterlab/jupyterlab/pull/5817), + [#4028](https://github.com/jupyterlab/jupyterlab/issues/4028)) +- If you link to a relative path that is not a file in a markdown + cell, this will now be preserved instead of changing it to a file + URL ([#5814](https://github.com/jupyterlab/jupyterlab/pull/5814)) +- Adds the ability to link to a certain row in a CSV file and have the + viewer open to that row + ([#5727](https://github.com/jupyterlab/jupyterlab/pull/5727), + [#5720](https://github.com/jupyterlab/jupyterlab/issues/5720)) +- We have improved the performance of switching to a large notebook + ([#5700](https://github.com/jupyterlab/jupyterlab/pull/5700), + [#4292](https://github.com/jupyterlab/jupyterlab/issues/4292), + [#2639](https://github.com/jupyterlab/jupyterlab/issues/2639)) +- The vdom extension now supports event handling, so that you can have + kernel code run in response to user interaction with the UI + ([#5670](https://github.com/jupyterlab/jupyterlab/pull/5670)) +- Adds the ability to run \"Run All Code\" and \"Restart Kernel and + Run All Code\" in code and markdown files + ([#5641](https://github.com/jupyterlab/jupyterlab/pull/5641), + [#5579](https://github.com/jupyterlab/jupyterlab/issues/5579)) +- We now remember what line ending a text file has when loading it, so + that files with `CRLF` line endings will properly be saved with the + same endings + ([#5622](https://github.com/jupyterlab/jupyterlab/pull/5622), + [#4464](https://github.com/jupyterlab/jupyterlab/issues/4464), + [#3901](https://github.com/jupyterlab/jupyterlab/issues/3901), + [#3706](https://github.com/jupyterlab/jupyterlab/issues/3706)) +- Fixes rendering of SVG elements in HTML MimeType output + ([#5610](https://github.com/jupyterlab/jupyterlab/pull/5610), + [#5610](https://github.com/jupyterlab/jupyterlab/issues/5610), + [#5589](https://github.com/jupyterlab/jupyterlab/issues/5589)) +- Allow copying files by holding down `Ctrl` when dragging them in the + file browser + ([#5584](https://github.com/jupyterlab/jupyterlab/pull/5584), + [#3235](https://github.com/jupyterlab/jupyterlab/issues/3235)) +- Switch the hover modified time in the file browser to use the local + format + ([#5567](https://github.com/jupyterlab/jupyterlab/pull/5567)) +- We have added a default keyboard shortcut of `Ctrl Shift Q` for + closing and cleaning up a file + ([#5534](https://github.com/jupyterlab/jupyterlab/pull/5534), + [#4390](https://github.com/jupyterlab/jupyterlab/issues/4390)) +- Adds the ability to find and go to a certain line in the CSV viewer + ([#5523](https://github.com/jupyterlab/jupyterlab/pull/5523)) +- Add the ability to create new text and markdown files from the + launcher and command palette + ([#5512](https://github.com/jupyterlab/jupyterlab/pull/5512), + [#5511](https://github.com/jupyterlab/jupyterlab/pull/5511)) +- A \"New Folder\" option has been added to the file browser context + menu ([#5447](https://github.com/jupyterlab/jupyterlab/pull/5447)) +- The ANSI colors are now the same as those in the classic notebook + ([#5336](https://github.com/jupyterlab/jupyterlab/pull/5336), + [#3773](https://github.com/jupyterlab/jupyterlab/issues/3773)) +- Send complete statements instead of current lines when stepping + through code in a cell + ([#6515](https://github.com/jupyterlab/jupyterlab/pull/6515), + [#6063](https://github.com/jupyterlab/jupyterlab/pull/6063)) +- Description list styles (`dl`, `dt`, `dd`) are improved to be + consistent with the nteract project + ([#5682](https://github.com/jupyterlab/jupyterlab/pull/5682), + [#2399](https://github.com/jupyterlab/jupyterlab/issues/2399)) + +### Settings + +- The settings system has been rewritten + ([#5470](https://github.com/jupyterlab/jupyterlab/pull/5470), + [#5298](https://github.com/jupyterlab/jupyterlab/issues/5298)) and + now uses json5 as the syntax, which supports comments and other + features for better human readability + ([#6343](https://github.com/jupyterlab/jupyterlab/pull/6343), + [#6199](https://github.com/jupyterlab/jupyterlab/issues/6199)). +- The keyboard shortcut system has been rewritten and now displays a + list of system commands in the settings comments + ([#5812](https://github.com/jupyterlab/jupyterlab/pull/5812), + [#5562](https://github.com/jupyterlab/jupyterlab/issues/5562)). + +There are new settings for many following items, including: + +- Adds an option to shut down terminals and notebook kernels when they + are closed + ([#6285](https://github.com/jupyterlab/jupyterlab/pull/6285), + [#6275](https://github.com/jupyterlab/jupyterlab/pull/6275)) +- Scrolling past the end of a notebooks and text editor document + ([#5542](https://github.com/jupyterlab/jupyterlab/pull/5542), + [#5271](https://github.com/jupyterlab/jupyterlab/issues/5271), + [#5652](https://github.com/jupyterlab/jupyterlab/pull/5652), + [#4429](https://github.com/jupyterlab/jupyterlab/issues/4429)) +- Text editor code folding, rulers, and active line highlighting + ([#5761](https://github.com/jupyterlab/jupyterlab/pull/5761), + [#4083](https://github.com/jupyterlab/jupyterlab/issues/4083), + [#5750](https://github.com/jupyterlab/jupyterlab/pull/5750), + [#4179](https://github.com/jupyterlab/jupyterlab/issues/4179), + [#5529](https://github.com/jupyterlab/jupyterlab/pull/5529), + [#5528](https://github.com/jupyterlab/jupyterlab/issues/5528)) +- Markdown viewer options + ([#5901](https://github.com/jupyterlab/jupyterlab/pull/5901), + [#3940](https://github.com/jupyterlab/jupyterlab/issues/3940)) +- Terminal scrollback and other settings + ([#5609](https://github.com/jupyterlab/jupyterlab/pull/5609), + [#3985](https://github.com/jupyterlab/jupyterlab/issues/3985)) +- The autosave interval + ([#5645](https://github.com/jupyterlab/jupyterlab/pull/5645), + [#5619](https://github.com/jupyterlab/jupyterlab/issues/5619)) +- The file browser showing the current active file + ([#5698](https://github.com/jupyterlab/jupyterlab/pull/5698), + [#4258](https://github.com/jupyterlab/jupyterlab/issues/4258)) +- Custom scrollbar styling for dark themes + ([#6026](https://github.com/jupyterlab/jupyterlab/pull/6026), + [#4867](https://github.com/jupyterlab/jupyterlab/issues/4867)) + +### Command Line Changes + +- Installing extensions will be quieter and adds a `--debug` to + extension installing + ([#6567](https://github.com/jupyterlab/jupyterlab/pull/6567), + [#6499](https://github.com/jupyterlab/jupyterlab/issues/6499), + [#5986](https://github.com/jupyterlab/jupyterlab/issues/5986)) +- We now support running JupyterLab when its application directory is + a symlink + ([#6240](https://github.com/jupyterlab/jupyterlab/pull/6240), + [#6166](https://github.com/jupyterlab/jupyterlab/issues/6166)) +- Add `--all` flag to `labextension uninstall` to remove all + extensions + ([#6058](https://github.com/jupyterlab/jupyterlab/pull/6058), + [#6006](https://github.com/jupyterlab/jupyterlab/issues/6006)) +- Adds the ability to override the base URLs from the config + ([#5518](https://github.com/jupyterlab/jupyterlab/pull/5518), + [#5503](https://github.com/jupyterlab/jupyterlab/pull/5503)) +- Updates to workspaces CLI command + ([#6473](https://github.com/jupyterlab/jupyterlab/pull/6473), + [#5977](https://github.com/jupyterlab/jupyterlab/issues/5977), + [#6276](https://github.com/jupyterlab/jupyterlab/pull/6276), + [#6234](https://github.com/jupyterlab/jupyterlab/pull/6234), + [#6210](https://github.com/jupyterlab/jupyterlab/issues/6210), + [#5975](https://github.com/jupyterlab/jupyterlab/pull/5975), + [#5695](https://github.com/jupyterlab/jupyterlab/pull/5695), + [#5694](https://github.com/jupyterlab/jupyterlab/issues/5694)) + +### Extension Development Changes + +- We have rewritten how extensions provide keyboard shortcuts and + interact with the settings system. If you previously defined + keyboard shortcuts or used the settings mechanism, you will need to + update your extension + ([#5470](https://github.com/jupyterlab/jupyterlab/pull/5470), + [#5298](https://github.com/jupyterlab/jupyterlab/issues/5298)) +- We have renamed the plugin type from `JupyterLabPlugin` to + `JupyterFrontEndPlugin`. The application arg is also renamed from + `JupyterLab` to `JupyterFrontEnd` and some its functionality has + been moved to a separate `ILabShell` plugin + ([#5845](https://github.com/jupyterlab/jupyterlab/pull/5845), + [#5919](https://github.com/jupyterlab/jupyterlab/pull/5919)) +- The lab shell `addToMainArea`, `addToLeftArea`, `addToTopArea`, + `addToRightArea`, and `addToBottomArea` functions have been replaced + with a single `add()` function that takes the area as an argument. + Replace `addToMainArea(widget, options)` with + `add(widget, 'main', options)`, etc. + ([#5845](https://github.com/jupyterlab/jupyterlab/pull/5845)) +- Rename `pageUrl` to `appUrl` in the server connection + ([#6509](https://github.com/jupyterlab/jupyterlab/pull/6509), + [#6508](https://github.com/jupyterlab/jupyterlab/issues/6508), + [#6585](https://github.com/jupyterlab/jupyterlab/pull/6585), + [#6584](https://github.com/jupyterlab/jupyterlab/issues/6584)) +- `MainAreaWidget` instances now forward update requests to their + `content` + ([#6586](https://github.com/jupyterlab/jupyterlab/pull/6586), + [#6571](https://github.com/jupyterlab/jupyterlab/issues/6571)) +- The theme data attributes are renamed and moved to the document body + element. If you are relying on these attributes in CSS to + conditionally style based on the theme, you should update their + names. For example `data-theme-light` is now `data-jp-theme-light`. + ([#6566](https://github.com/jupyterlab/jupyterlab/pull/6566), + [#6554](https://github.com/jupyterlab/jupyterlab/issues/6554)) +- Extensions which require CSS should no longer import their CSS files + into their Javascript files. Instead, they should specify a root CSS + file in the `style` attribute in their `package.json`, and + JupyterLab will automatically import that CSS file. + ([#6533](https://github.com/jupyterlab/jupyterlab/pull/6533), + [#6530](https://github.com/jupyterlab/jupyterlab/issues/6530), + [#6395](https://github.com/jupyterlab/jupyterlab/pull/6395), + [#6390](https://github.com/jupyterlab/jupyterlab/issues/6390)) +- `Dialog.prompt` has been replaced by a number of type-specific + dialogs such as `InputDialog.getString`, `InputDialog.getBoolean`, + etc. ([#6522](https://github.com/jupyterlab/jupyterlab/pull/6522), + [#6378](https://github.com/jupyterlab/jupyterlab/issues/6378), + [#6327](https://github.com/jupyterlab/jupyterlab/pull/6327), + [#6326](https://github.com/jupyterlab/jupyterlab/issues/6326)) +- When a `RenderMime` widget is re-rendered, the default behavior is + to remove any existing content in the DOM. This can be overridden if + needed. + ([#6513](https://github.com/jupyterlab/jupyterlab/pull/6513), + [#6505](https://github.com/jupyterlab/jupyterlab/issues/6505), + [#6497](https://github.com/jupyterlab/jupyterlab/issues/6497)) +- We have updated our internal TypeScript version to 3.5.1 and our + compile target to `ES2017`. Extensions may need to upgrade their + TypeScript version and target as well. + ([#6440](https://github.com/jupyterlab/jupyterlab/pull/6440), + [#6224](https://github.com/jupyterlab/jupyterlab/pull/6224)) +- We have updated the typings for some of the Kernel messages so that + they better match the spec. + ([#6433](https://github.com/jupyterlab/jupyterlab/pull/6433)) +- A `connectionFailure` signal has been added to some of the manager + classes, which can be used to detect when a connection to the server + is lost + ([#6399](https://github.com/jupyterlab/jupyterlab/pull/6399), + [#6176](https://github.com/jupyterlab/jupyterlab/issues/6176), + [#3324](https://github.com/jupyterlab/jupyterlab/issues/3324)) +- Add rate limiting and polling utilities to `coreutils` to use for + throttling and debouncing of API requests + ([#6345](https://github.com/jupyterlab/jupyterlab/pull/6345), + [#6346](https://github.com/jupyterlab/jupyterlab/issues/6346), + [#6401](https://github.com/jupyterlab/jupyterlab/pull/6401), + [#6305](https://github.com/jupyterlab/jupyterlab/pull/6305), + [#6157](https://github.com/jupyterlab/jupyterlab/issues/6157), + [#6192](https://github.com/jupyterlab/jupyterlab/pull/6192), + [#6186](https://github.com/jupyterlab/jupyterlab/pull/6186), + [#6141](https://github.com/jupyterlab/jupyterlab/pull/6141), + [#3929](https://github.com/jupyterlab/jupyterlab/issues/3929), + [#6141](https://github.com/jupyterlab/jupyterlab/pull/6141), + [#3929](https://github.com/jupyterlab/jupyterlab/issues/3929), + [#6186](https://github.com/jupyterlab/jupyterlab/pull/6186), + [#6192](https://github.com/jupyterlab/jupyterlab/pull/6192), + [#6401](https://github.com/jupyterlab/jupyterlab/pull/6401) + ,[#6305](https://github.com/jupyterlab/jupyterlab/pull/6305), + [#6157](https://github.com/jupyterlab/jupyterlab/issues/6157)) +- Require session when instantiating terminal widget + ([#6339](https://github.com/jupyterlab/jupyterlab/pull/6339), + [#5061](https://github.com/jupyterlab/jupyterlab/issues/5061)) +- Provides a signal to see what items are opened in a directory + listing + ([#6270](https://github.com/jupyterlab/jupyterlab/pull/6270), + [#6269](https://github.com/jupyterlab/jupyterlab/issues/6269)) +- Ads the ability to add widget above the main work area to a top + header area + ([#5936](https://github.com/jupyterlab/jupyterlab/pull/5936)) +- Renames `contextMenuFirst` to `contextMenuHitTest` in the + `JupyterFrontEnd` + ([#5932](https://github.com/jupyterlab/jupyterlab/pull/5932)) +- Removes the `initialCommand` arg from the terminal creation command. + ([#5916](https://github.com/jupyterlab/jupyterlab/pull/5916)) +- Adds `--jp-code-cursor-width0`, `--jp-code-cursor-width1`, and + `--jp-code-cursor-width2` variables to the themes to support + changing the cursor width if you change the font size + ([#5898](https://github.com/jupyterlab/jupyterlab/pull/5898)) +- Adds the ability to insert a new item to the toolbar before or after + another item + ([#5896](https://github.com/jupyterlab/jupyterlab/pull/5896), + [#5894](https://github.com/jupyterlab/jupyterlab/issues/5894)) +- Adds the ability for extensions to register new CodeMirror modes + ([#5829](https://github.com/jupyterlab/jupyterlab/pull/5829)) +- We have removed the `JUPYTERLAB_xxx_LOADER` Webpack loaders, instead + you should use the loader directly in the URL as Webpack supports it + ([#5709](https://github.com/jupyterlab/jupyterlab/pull/5709), + [#4406](https://github.com/jupyterlab/jupyterlab/issues/4406)) +- Adds the ability to handle fragments for document widgets + ([#5630](https://github.com/jupyterlab/jupyterlab/pull/5630), + [#5599](https://github.com/jupyterlab/jupyterlab/issues/5599)) +- We have added a `@jupyterlab/ui-components` package that contains + reusable React components to be used internally and in extensions. + Feel free to use this to create extension UIs with consistent styles + ([#5538](https://github.com/jupyterlab/jupyterlab/pull/5538)) +- The `showErrorMessage` function now lets you customize the buttons + it uses + ([#5513](https://github.com/jupyterlab/jupyterlab/pull/5513)) +- We now provide helpers for using React components within JupyterLab. + If you were previously using `ReactElementWidget` you should switch + to using `ReactWidget`. + ([#5479](https://github.com/jupyterlab/jupyterlab/pull/5479), + [#5766](https://github.com/jupyterlab/jupyterlab/issues/5766), + [#6595](https://github.com/jupyterlab/jupyterlab/pull/6595), + [#6595](https://github.com/jupyterlab/jupyterlab/pull/6595)) +- The share link command has been moved to its own extension so that + it can be overridden + ([#5460](https://github.com/jupyterlab/jupyterlab/pull/5460), + [#5388](https://github.com/jupyterlab/jupyterlab/issues/5388)) +- Creating a new services session now requires passing a kernel model + instead of a kernel instance + ([#6503](https://github.com/jupyterlab/jupyterlab/pull/6503), + [#6142](https://github.com/jupyterlab/jupyterlab/issues/6142)) +- We upgraded the Webpack raw file loader. The new version of the raw + loader exports ES2015 modules, so this may require changes in + extensions that import files using the raw loader. For example, if + you did `require('myfile.md')` to get the content of + `myfile.md` as a string, you now should import it using + ES2015 `import` syntax, or use + `require(\'myfile.md\').default`. +- Widget factories now can support custom cloning behavior from an + optional source widget + ([#6060](https://github.com/jupyterlab/jupyterlab/pull/6060), + [#6044](https://github.com/jupyterlab/jupyterlab/issues/6044)) +- We have renamed the type `InstanceTracker` to `WidgetTracker` + ([#6569](https://github.com/jupyterlab/jupyterlab/commit/da8e7bda5eebd22319f59e5abbaaa9917872a7e8)). +- In order to add widgets to the main area (e.g. as in the old XKCD + extension tutorial), the correct syntax is now + `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) + +### 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 + +- A notebook cell can now be readonly, reflecting its `enabled` + metadata. + ([#5401](https://github.com/jupyterlab/jupyterlab/pull/5401), + [#1312](https://github.com/jupyterlab/jupyterlab/issues/1312)) +- Add \"Go To Line\" in the Edit menu for text editors. + ([#5377](https://github.com/jupyterlab/jupyterlab/pull/5377)) +- Sidebar panels can now be switched between left and right sidebars. + Right-click on a sidebar tab to move it to the other sidebar. + ([#5347](https://github.com/jupyterlab/jupyterlab/pull/5347), + [#5054](https://github.com/jupyterlab/jupyterlab/issues/5054), + [#3707](https://github.com/jupyterlab/jupyterlab/issues/3707)) +- Make the sidebar a bit narrower, and make the minimum width + adjustable from a theme. + ([#5245](https://github.com/jupyterlab/jupyterlab/pull/5245)) +- Populate the File, Export Notebook As\... submenu from the server + nbconvert capabilities. + ([#5217](https://github.com/jupyterlab/jupyterlab/pull/5217)) +- Server contents managers can now tell JupyterLab to open files as + notebooks. For example, several custom contents managers save and + open notebooks as Markdown files. + ([#5247](https://github.com/jupyterlab/jupyterlab/pull/5247), + [#4924](https://github.com/jupyterlab/jupyterlab/issues/4924)) +- Add a command-line interface for managing workspaces. + ([#5166](https://github.com/jupyterlab/jupyterlab/pull/5166)) +- Allow safe inline CSS styles in Markdown. + ([#5012](https://github.com/jupyterlab/jupyterlab/pull/5012), + [#1812](https://github.com/jupyterlab/jupyterlab/issues/1812)) +- Add Quit to File menu when appropriate. + ([#5226](https://github.com/jupyterlab/jupyterlab/pull/5226), + [#5252](https://github.com/jupyterlab/jupyterlab/pull/5252), + [#5246](https://github.com/jupyterlab/jupyterlab/issues/5246), + [#5280](https://github.com/jupyterlab/jupyterlab/pull/5280)) +- Rework extension manager user experience. + ([#5147](https://github.com/jupyterlab/jupyterlab/pull/5147), + [#5042](https://github.com/jupyterlab/jupyterlab/issues/5042)) + +### Dark theme + +- Show a dark splash screen when using a dark theme. + ([#5339](https://github.com/jupyterlab/jupyterlab/pull/5339), + [#5338](https://github.com/jupyterlab/jupyterlab/issues/5338), + [#5403](https://github.com/jupyterlab/jupyterlab/pull/5403)) +- Fix code completion menu for a dark theme. + ([#5364](https://github.com/jupyterlab/jupyterlab/pull/5364), + [#5349](https://github.com/jupyterlab/jupyterlab/issues/5349)) +- Style CSV viewer for a dark theme. + ([#5304](https://github.com/jupyterlab/jupyterlab/pull/5304), + [#3456](https://github.com/jupyterlab/jupyterlab/issues/3456)) +- Make Matplotlib figures legible in a dark theme. + ([#5232](https://github.com/jupyterlab/jupyterlab/pull/5232)) +- Fix notebook cell dropdown legibility in a dark theme. + ([#5168](https://github.com/jupyterlab/jupyterlab/issues/5168)) + +### Bug fixes + +- Various save options in the file menu and toolbar are now disabled + when a file is not writable. + ([#5376](https://github.com/jupyterlab/jupyterlab/pull/5376), + [#5391](https://github.com/jupyterlab/jupyterlab/pull/5391)) +- Kernel selector dialog no longer cuts off kernel names. + ([#5260](https://github.com/jupyterlab/jupyterlab/pull/5260), + [#5181](https://github.com/jupyterlab/jupyterlab/issues/5181)) +- Fix focus issues with the toolbar. + ([#5344](https://github.com/jupyterlab/jupyterlab/pull/5344), + [#5324](https://github.com/jupyterlab/jupyterlab/pull/5324), + [#2995](https://github.com/jupyterlab/jupyterlab/issues/2995), + [#5328](https://github.com/jupyterlab/jupyterlab/pull/5328)) +- Fix toolbar button enabled/disabled status. + ([#5278](https://github.com/jupyterlab/jupyterlab/pull/5278)) +- Table alignment is now respected in Markdown. + ([#5301](https://github.com/jupyterlab/jupyterlab/pull/5301), + [#3180](https://github.com/jupyterlab/jupyterlab/issues/3180)) +- Fix syntax highlighting for Markdown lists. + ([#5297](https://github.com/jupyterlab/jupyterlab/pull/5297), + [#2741](https://github.com/jupyterlab/jupyterlab/issues/2741)) +- Use the current filebrowser instead of the default one for various + commands. + ([#5390](https://github.com/jupyterlab/jupyterlab/pull/5390)) +- Fix escaping in link handling to conform to Markdown syntax. This + means that spaces in link references now need to be encoded as + `%20`. + ([#5383](https://github.com/jupyterlab/jupyterlab/pull/5383), + [#5340](https://github.com/jupyterlab/jupyterlab/pull/5340), + [#5153](https://github.com/jupyterlab/jupyterlab/issues/5153)) + +### Build system + +- Use Typescript 3.1. + ([#5360](https://github.com/jupyterlab/jupyterlab/pull/5360)) +- Use Lerna 3.2.1. + ([#5262](https://github.com/jupyterlab/jupyterlab/pull/5262)) +- Node \>=6.11.5 is now required. + ([#5227](https://github.com/jupyterlab/jupyterlab/pull/5227)) +- Pin vega-embed version to 3.18.2. + ([#5342](https://github.com/jupyterlab/jupyterlab/pull/5342)) +- Use Jest for services tests. + ([#5251](https://github.com/jupyterlab/jupyterlab/pull/5251), + [#5282](https://github.com/jupyterlab/jupyterlab/pull/5282)) +- Make it easier for third party extensions to use the JupyterLab test + app and testing utilities. + ([#5415](https://github.com/jupyterlab/jupyterlab/pull/5415)) +- Fix `jupyter lab clean` on Windows. + ([#5400](https://github.com/jupyterlab/jupyterlab/pull/5400), + [#5397](https://github.com/jupyterlab/jupyterlab/issues/5397)) +- Fix `jupyter lab build` on NFS. + ([#5237](https://github.com/jupyterlab/jupyterlab/pull/5237), + [#5233](https://github.com/jupyterlab/jupyterlab/issues/5233)) +- Build wheels for Python 3 only. + ([#5287](https://github.com/jupyterlab/jupyterlab/pull/5287)) +- Migrate to using `jupyterlab_server` instead of + `jupyterlab_launcher` and fix the app example. + ([#5316](https://github.com/jupyterlab/jupyterlab/pull/5316)) +- Move Mathjax 2 typesetter to a library package. + ([#5259](https://github.com/jupyterlab/jupyterlab/pull/5259), + [#5257](https://github.com/jupyterlab/jupyterlab/issues/5257)) + +### For Developers + +- Default toolbar buttons can be overridden, and mime renderers can + now specify toolbar buttons. + ([#5398](https://github.com/jupyterlab/jupyterlab/pull/5398), + [#5370](https://github.com/jupyterlab/jupyterlab/pull/5370), + [#5363](https://github.com/jupyterlab/jupyterlab/issues/5363)) +- A JupyterLab application instance can now be given a document + 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) + +### 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 + +- Notebooks, consoles, and text files now have access to completions + for local tokens. +- Python 3.5+ is now required to use JupyterLab. Python 2 kernels can + still be run within JupyterLab. +- Added the pipe (`|`) character as a CSV delimiter option. +- Added \"Open From Path\...\"\" to top level `File` menu. +- Added \"Copy Download Link\" to context menu for files. + +### 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 + with its path (as happens with an attached console), it also gets + completions and tooltips from that kernel. + ([#5049](https://github.com/jupyterlab/jupyterlab/pull/5049)) + +- The `FileBrowser` widget has a new constructor option + `refreshInterval`, allowing the creator to customize how often the + widget polls the storage backend. This can be useful to prevent + rate-limiting in certain contexts. + ([#5048](https://github.com/jupyterlab/jupyterlab/pull/5048)) + +- The application shell now gets a pair of CSS data attributes + indicating the current theme, and whether it is light or dark. + Extension authors can write CSS rules targeting these to have their + extension UI elements respond to the application theme. For + instance, to write a rule targeting whether the theme is overall + light or dark, you can use + + ```css + [data-theme-light='true'] your-ui-class { + background-color: white; + } + [data-theme-light='false'] your-ui-class { + background-color: black; + } + ``` + + The theme name can also be targeted by writing CSS rules for + `data-theme-name`. + ([#5078](https://github.com/jupyterlab/jupyterlab/pull/5078)) + +- The `IThemeManager` interface now exposes a signal for + `themeChanged`, allowing extension authors to react to changes in + the theme. Theme extensions must also provide a new boolean property + `isLight`, declaring whether they are broadly light colored. This + data allows third-party extensions to react better to the active + application theme. + ([#5078](https://github.com/jupyterlab/jupyterlab/pull/5078)) + +- Added a patch to update the `uploads` for each `FileBrowserModel` + instantly whenever a file upload errors. Previously, the upload that + erred was only being removed from uploads upon an update. This would + allow the status bar component and other extensions that use the + `FileBrowserModel` to be more precise. + ([#5077](https://github.com/jupyterlab/jupyterlab/pull/5077)) + +- Cell IDs are now passed in the shell message as part of the cell + metadata when a cell is executed. This helps in developing reactive + kernels. + ([#5033](https://github.com/jupyterlab/jupyterlab/pull/5033)) + +- The IDs of all deleted cells since the last run cell are now passed + as part of the cell metadata on execution. The IDs of deleted cells + since the last run cell are stored as `deletedCells` in + `NotebookModel`. This helps in developing reactive kernels. + ([#5037](https://github.com/jupyterlab/jupyterlab/pull/5037)) + +- The `ToolbarButton` in `apputils` has been refactored with an API + change and now uses a React component `ToolbarButtonComponent` to + render its children. It is now a `div` with a single `button` child, + which in turn as two `span` elements for an icon and text label. + Extensions that were using the `className` options should rename it + as `iconClassName`. The `className` options still exists, but it + used as the CSS class on the `button` element itself. The API + changes were done to accommodate styling changes to the button. + ([#5117](https://github.com/jupyterlab/jupyterlab/pull/5117)) + +- The `Toolbar.createFromCommand` function has been replaced by a + dedicated `ToolbarButton` subclass called `CommandToolbarButton`, + that wraps a similarly named React component. + ([#5117](https://github.com/jupyterlab/jupyterlab/pull/5117)) + +- The design and styling of the right and left sidebars tabs has been + improved to address + [#5054](https://github.com/jupyterlab/jupyterlab/issues/50). We are + now using icons to render tabs for the extensions we ship with + JupyterLab and extension authors are encouraged to do the same (text + labels still work). Icon based tabs can be used by removing + `widget.caption` and adding + `widget.iconClass = ' jp-SideBar-tabIcon';`. + ([#5117](https://github.com/jupyterlab/jupyterlab/pull/5117)) + +- The style of buttons in JupyterLab has been updated to a borderless + design. + ([#5117](https://github.com/jupyterlab/jupyterlab/pull/5117)) + +- A new series of helper CSS classes for stying SVG-based icons at + different sizes has been added: `jp-Icon`, `jp-Icon-16`, + `jp-Icon-18`, `jp-Icon-20`. + +- The rank of the default sidebar widget has been updated. The main + change is giving the extension manager a rank of `1000` so that it + appears at the end of the default items. + +- Python 3.5+ is now required to use JupyterLab. Python 2 kernels can + still be run within JupyterLab. + ([#5119](https://github.com/jupyterlab/jupyterlab/pull/5119)) + +- JupyterLab now uses `yarn 1.9.4` (aliased as `jlpm`), which now + allows uses to use Node 10+. + ([#5121](https://github.com/jupyterlab/jupyterlab/pull/5121)) + +- Clean up handling of `baseUrl` and `wsURL` for `PageConfig` and + `ServerConnection`. + ([#5111](https://github.com/jupyterlab/jupyterlab/pull/5111)) + +### Other Changes + +- Added the pipe (`|`) character as a CSV delimiter option. + ([#5112](https://github.com/jupyterlab/jupyterlab/pull/5112)) +- Added `Open From Path...` to top level `File` menu. + ([#5108](https://github.com/jupyterlab/jupyterlab/pull/5108)) +- Added a `saveState` signal to the document context object. + ([#5096](https://github.com/jupyterlab/jupyterlab/pull/5096)) +- Added \"Copy Download Link\" to context menu for files. + ([#5089](https://github.com/jupyterlab/jupyterlab/pull/5089)) +- Extensions marked as `deprecated` are no longer shown in the + extension manager. + ([#5058](https://github.com/jupyterlab/jupyterlab/pull/5058)) +- Remove `In` and `Out` text from cell prompts. Shrunk the prompt + width from 90px to 64px. In the light theme, set the prompt colors + of executed console cells to active prompt colors and reduced their + opacity to 0.5. In the dark theme, set the prompt colors of executed + console cells to active prompt colors and set their opacity to 1. + ([#5097](https://github.com/jupyterlab/jupyterlab/pull/5097) and + [#5130](https://github.com/jupyterlab/jupyterlab/pull/5130)) + +### Bug Fixes + +- Fixed a bug in the rendering of the \"New Notebook\" item of the + command palette. + ([#5079](https://github.com/jupyterlab/jupyterlab/pull/5079)) +- We only create the extension manager widget if it is enabled. This + prevents unnecessary network requests to `npmjs.com`. + ([#5075](https://github.com/jupyterlab/jupyterlab/pull/5075)) +- The `running` panel now shows the running sessions at startup. + ([#5118](https://github.com/jupyterlab/jupyterlab/pull/5118)) +- Double clicking a file in the file browser always opens it rather + 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) + +### July 26, 2018 + +See the [JupyterLab +0.33.0](https://github.com/jupyterlab/jupyterlab/milestone/12?closed=1) +milestone on GitHub for the full list of pull requests and issues +closed. + +### 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 + +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 +developer API is still being stabilized. See the release blog post for +details. +([#4898](https://github.com/jupyterlab/jupyterlab/issues/4898), +[#4920](https://github.com/jupyterlab/jupyterlab/pull/4920)) + +### Workspaces + +We added new workspace support, which enables you to have multiple saved +layouts, including in different browser windows. See the +`workspace documentation` for more details. +([#4502](https://github.com/jupyterlab/jupyterlab/issues/4502), +[#4708](https://github.com/jupyterlab/jupyterlab/pull/4708), +[#4088](https://github.com/jupyterlab/jupyterlab/issues/4088), +[#4041](https://github.com/jupyterlab/jupyterlab/pull/4041) +[#3673](https://github.com/jupyterlab/jupyterlab/issues/3673), +[#4780](https://github.com/jupyterlab/jupyterlab/pull/4780)) + +### Menu items + +- "Activate Previously Used Tab" added to the Tab menu + (`Ctrl/Cmd Shift '`) to toggle between the previously active tabs in + the main area. + ([#4296](https://github.com/jupyterlab/jupyterlab/pull/4296)) +- "Reload From Disk" added to the File menu to reload an open file + from the state saved on disk. + ([#4615](https://github.com/jupyterlab/jupyterlab/pull/4615)) +- "Save Notebook with View State" added to the File menu to persist + the notebook collapsed and scrolled cell state. We now read the + `collapsed`, `scrolled`, `jupyter.source_hidden` and + `jupyter.outputs_hidden` notebook cell metadata when opening. + `collapsed` and `jupyter.outputs_hidden` are redundant and the + initial collapsed state is the union of both of them. When the state + is persisted, if an output is collapsed, both will be written with + the value `true`, and if it is not, both will not be written. + ([#3981](https://github.com/jupyterlab/jupyterlab/pull/3981)) +- "Increase/Decrease Font Size" added to the text editor settings + menu. ([#4811](https://github.com/jupyterlab/jupyterlab/pull/4811)) +- "Show in File Browser" added to a document tab's context menu. + ([#4500](https://github.com/jupyterlab/jupyterlab/pull/4500)) +- "Open in New Browser Tab" added to the file browser context menu. + ([#4315](https://github.com/jupyterlab/jupyterlab/pull/4315)) +- "Copy Path" added to file browser context menu to copy the + document's path to the clipboard. + ([#4582](https://github.com/jupyterlab/jupyterlab/pull/4582)) +- "Show Left Area" has been renamed to "Show Left Sidebar" for + consistency (same for right sidebar). + ([#3818](https://github.com/jupyterlab/jupyterlab/pull/3818)) + +### Keyboard shortcuts + +- "Save As..." given the keyboard shortcut `Ctrl/Cmd Shift S`. + ([#4560](https://github.com/jupyterlab/jupyterlab/pull/4560)) +- "Run All Cells" given the keyboard shortcut `Ctrl/Cmd Shift Enter`. + ([#4558](https://github.com/jupyterlab/jupyterlab/pull/4558)) +- "notebook:change-to-cell-heading-X" keyboard shortcuts (and + commands) renamed to "notebook:change-cell-to-heading-X" for + X=1...6. This fixes the notebook command-mode keyboard shortcuts for + changing headings. + ([#4430](https://github.com/jupyterlab/jupyterlab/pull/4430)) +- The console execute shortcut can now be set to either `Enter` or + `Shift Enter` as a Console setting. + ([#4054](https://github.com/jupyterlab/jupyterlab/pull/4054)) + +### Command palette items + +- "Notebook" added to the command palette to open a new notebook. + ([#4812](https://github.com/jupyterlab/jupyterlab/pull/4812)) + +- "Run Selected Text or Current Line in Console" added to the command + palette to run the selected text or current line from a notebook in + a console. A default keyboard shortcut for this command is not yet + provided, but can be added by users with the + `notebook:run-in-console` command. To add a keyboard shortcut + `Ctrl G` for this command, use the "Settings" \| "Advanced Settings + Editor" menu item to open the "Keyboard Shortcuts" advanced + settings, and add the following JSON in the shortcut JSON object in + the User Overrides pane (adjust the actual keyboard shortcut if you + wish). + ([#3453](https://github.com/jupyterlab/jupyterlab/issues/3453), + [#4206](https://github.com/jupyterlab/jupyterlab/issues/4206), + [#4330](https://github.com/jupyterlab/jupyterlab/pull/4330)) + + ```json + { + "command": "notebook:run-in-console", + "keys": ["Ctrl G"], + "selector": ".jp-Notebook.jp-mod-editMode" + } + ``` + +- The command palette now renders labels, toggled state, and keyboard + shortcuts in a more consistent and correct way. + ([#4533](https://github.com/jupyterlab/jupyterlab/pull/4533), + [#4510](https://github.com/jupyterlab/jupyterlab/pull/4510)) + +### Settings + +- "fontFamily", "fontSize", and "lineHeight" settings added to the + text editor advanced settings. + ([#4673](https://github.com/jupyterlab/jupyterlab/pull/4673)) +- Solarized dark and light text editor themes from CodeMirror. + ([#4445](https://github.com/jupyterlab/jupyterlab/pull/4445)) + +### 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 + +- New extension manager for installing JupyterLab extensions from npm + within the JupyterLab UI. You can enable this from the Advanced + Settings interface. + ([#4682](https://github.com/jupyterlab/jupyterlab/pull/4682), + [#4925](https://github.com/jupyterlab/jupyterlab/pull/4925)) +- Please note that to install extensions in JupyterLab, you must use + NodeJS version 9 or earlier (i.e., not NodeJS version 10). We will + upgrade yarn, with NodeJS version 10 support, when a [bug in + yarn](https://github.com/yarnpkg/yarn/issues/5935) is fixed. + ([#4804](https://github.com/jupyterlab/jupyterlab/pull/4804)) + +### Interface changes + +- Wider tabs in the main working area to show longer filenames. + ([#4801](https://github.com/jupyterlab/jupyterlab/pull/4801)) +- Initial kernel selection for a notebook or console can no longer be + canceled: the user must select a kernel. + ([#4596](https://github.com/jupyterlab/jupyterlab/pull/4596)) +- Consoles now do not display output from other clients by default. A + new "Show All Kernel Activity" console context menu item has been + added to show all activity from a kernel in the console. + ([#4503](https://github.com/jupyterlab/jupyterlab/pull/4503)) +- The favicon now shows the busy status of the kernels in JupyterLab. + ([#4361](https://github.com/jupyterlab/jupyterlab/pull/4361), + [#3957](https://github.com/jupyterlab/jupyterlab/issues/3957), + [#4966](https://github.com/jupyterlab/jupyterlab/pull/4966)) + +### Renderers + +- JupyterLab now ships with a Vega4 renderer by default (upgraded from + Vega3). + ([#4806](https://github.com/jupyterlab/jupyterlab/pull/4806)) +- The HTML sanitizer now allows some extra tags in rendered HTML, + including `kbd`, `sup`, and `sub`. + ([#4618](https://github.com/jupyterlab/jupyterlab/pull/4618)) +- JupyterLab now recognizes the `.tsv` file extension as tab-separated + files. + ([#4684](https://github.com/jupyterlab/jupyterlab/pull/4684)) +- Javascript execution in notebook cells has been re-enabled. + ([#4515](https://github.com/jupyterlab/jupyterlab/pull/4682)) + +### Changes for developers + +- A new signal for observing application dirty status state changes. + ([#4840](https://github.com/jupyterlab/jupyterlab/issues/4840)) +- A new signal for observing notebook cell execution. + ([#4740](https://github.com/jupyterlab/jupyterlab/issues/4740), + [#4744](https://github.com/jupyterlab/jupyterlab/pull/4744)) +- A new `anyMessage` signal for observing any message a kernel sends + or receives. + ([#4437](https://github.com/jupyterlab/jupyterlab/pull/4437)) +- A generic way for different widgets to register a "Save with extras" + command that appears in the File menu under save. + ([#3981](https://github.com/jupyterlab/jupyterlab/pull/3981)) +- A new API for removing groups from a JupyterLab menu. `addGroup` now + returns an `IDisposable` which can be used to remove the group. + `removeGroup` has been removed. + ([#4890](https://github.com/jupyterlab/jupyterlab/pull/4890)) +- The `Launcher` now uses commands from the application + `CommandRegistry` to launch new activities. Extension authors that + add items to the launcher will need to update them to use commands. + ([#4757](https://github.com/jupyterlab/jupyterlab/pull/4757)) +- There is now a top-level `addToBottomArea` function in the + application, allowing extension authors to add bottom panel items + like status bars. + ([#4752](https://github.com/jupyterlab/jupyterlab/pull/4752)) +- Rendermime extensions can now indicate that they are the default + rendered widget factory for a file-type. For instance, the default + widget for a markdown file is a text editor, but the default + rendered widget is the markdown viewer. + ([#4692](https://github.com/jupyterlab/jupyterlab/pull/4692)) +- Add new workspace REST endpoints to `jupyterlab_server` and make + them available in `@jupyterlab/services`. + ([#4841](https://github.com/jupyterlab/jupyterlab/pull/4841)) +- Documents created with a mimerenderer extension can now be accessed + using an `IInstanceTracker` which tracks them. Include the token + `IMimeDocumentTracker` in your plugin to access this. The + `IInstanceTracker` interface has also gained convenience functions + `find` and `filter` to simplify iterating over instances. + ([#4762](https://github.com/jupyterlab/jupyterlab/pull/4762)) +- RenderMime render errors are now displayed to the user. + ([#4465](https://github.com/jupyterlab/jupyterlab/pull/4465)) +- `getNotebookVersion` is added to the `PageConfig` object. + ([#4224](https://github.com/jupyterlab/jupyterlab/pull/4224)) +- The session `kernelChanged` signal now contains both the old kernel + and the new kernel to make it easy to unregister things from the old + kernel. + ([#4834](https://github.com/jupyterlab/jupyterlab/pull/4834)) +- The `connectTo` functions for connecting to kernels and sessions are + now synchronous (returning a connection immediately rather than a + promise). The DefaultSession `clone` and `update` methods are also + synchronous now. + ([#4725](https://github.com/jupyterlab/jupyterlab/pull/4725)) +- Kernel message processing is now asynchronous, which guarantees the + order of processing even if a handler is asynchronous. If a kernel + message handler returns a promise, kernel message processing is + paused until the promise resolves. The kernel's `anyMessage` signal + is emitted synchronously when a message is received before + asynchronous message handling, and the `iopubMessage` and + `unhandledMessage` signals are emitted during asynchronous message + handling. These changes mean that the comm `onMsg` and `onClose` + handlers and the kernel future `onReply`, `onIOPub`, and `onStdin` + handlers, as well as the comm target and message hook handlers, may + be asynchronous and return promises. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- Kernel comm targets and message hooks now are unregistered with + `removeCommTarget` and `removeMessageHook`, instead of using + disposables. The corresponding `registerCommTarget` and + `registerMessageHook` functions now return nothing. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- The kernel `connectToComm` function is synchronous, and now returns + the comm rather than a promise to the comm. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- The `KernelFutureHandler` class `expectShell` constructor argument + is renamed to `expectReply`. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- The kernel future `done` returned promise now resolves to undefined + if there is no reply message. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- The `IDisplayDataMsg` is updated to have the optional `transient` + key, and a new `IUpdateDisplayDataMsg` type was added for update + display messages. + ([#4697](https://github.com/jupyterlab/jupyterlab/pull/4697)) +- The `uuid` function from `@jupyterlab/coreutils` is removed. Instead + import `UUID` from `@phosphor/coreutils` and use `UUID.uuid4()` . + ([#4604](https://github.com/jupyterlab/jupyterlab/pull/4604)) +- Main area widgets like the launcher and console inherit from a + common `MainAreaWidget` class which provides a content area + (`.content`) and a toolbar (`.toolbar`), consistent focus handling + and activation behavior, and a spinner displayed until the given + `reveal` promise is resolved. Document widgets, like the notebook + and text editor and other documents opened from the document + manager, implement the `IDocumentWidget` interface (instead of + `DocumentRegistry.IReadyWidget`), which builds on `MainAreaWidget` + and adds a `.context` attribute for the document context and makes + dirty handling consistent. Extension authors may consider inheriting + from the `MainAreaWidget` or `DocumentWidget` class for consistency. + Several effects from these changes are noted below. + ([#3499](https://github.com/jupyterlab/jupyterlab/pull/3499), + [#4453](https://github.com/jupyterlab/jupyterlab/pull/4453)) + - The notebook panel `.notebook` attribute is renamed to + `.content`. + - The text editor is now the `.content` of a `DocumentWidget`, so + the top-level editor widget has a toolbar and the editor itself + is `widget.content.editor` rather than just `widget.editor`. + - Mime documents use a `MimeContent` widget embedded inside of a + `DocumentWidget` now. + - Main area widgets and document widgets now have a `revealed` + promise which resolves when the widget has been revealed (i.e., + the spinner has been removed). This should be used instead of + the `ready` promise. + +Changes in the JupyterLab code infrastructure include: + +- The JupyterLab TypeScript codebase is now compiled to ES2015 (ES6) + using TypeScript 2.9. We also turned on the TypeScript + `esModuleInterop` flag to enable more natural imports from + non-es2015 JavaScript modules. With the update to ES2015 output, + code generated from async/await syntax became much more manageable, + so we have started to use async/await liberally throughout the + codebase, especially in tests. Because we use Typedoc for API + documentation, we still use syntax compatible with TypeScript 2.7 + where Typedoc is used. Extension authors may have some minor + compatibility updates to make. If you are writing an extension in + TypeScript, we recommend updating to TypeScript 2.9 and targeting + ES2015 output as well. + ([#4462](https://github.com/jupyterlab/jupyterlab/pull/4462), + [#4675](https://github.com/jupyterlab/jupyterlab/pull/4675), + [#4714](https://github.com/jupyterlab/jupyterlab/pull/4714), + [#4797](https://github.com/jupyterlab/jupyterlab/pull/4797)) +- The JupyterLab codebase is now formatted using + [Prettier](https://github.com/prettier/prettier). By default the + development environment installs a pre-commit hook that formats your + staged changes. + ([#4090](https://github.com/jupyterlab/jupyterlab/pull/4090)) +- Updated build infrastructure using webpack 4 and better typing. + ([#4702](https://github.com/jupyterlab/jupyterlab/pull/4702), + [#4698](https://github.com/jupyterlab/jupyterlab/pull/4698)) +- Upgraded yarn to version 1.6. Please note that you must use NodeJS + version 9 or earlier with JupyterLab (i.e., not NodeJS version 10). + We will upgrade yarn, with NodeJS version 10 support, when a [bug in + yarn](https://github.com/yarnpkg/yarn/issues/5935) is fixed. + ([#4804](https://github.com/jupyterlab/jupyterlab/pull/4804)) +- Various process utilities were moved to `jupyterlab_server`. + ([#4696](https://github.com/jupyterlab/jupyterlab/pull/4696)) + +### Other fixes + +- Fixed a rendering bug with the Launcher in single-document mode. + ([#4805](https://github.com/jupyterlab/jupyterlab/pull/4805)) +- Fixed a bug where the native context menu could not be triggered in + a notebook cell in Chrome. + ([#4720](https://github.com/jupyterlab/jupyterlab/pull/4720)) +- Fixed a bug where the cursor would not show up in the dark theme. + ([#4699](https://github.com/jupyterlab/jupyterlab/pull/4699)) +- Fixed a bug preventing relative links from working correctly in + alternate `IDrive`s. + ([#4613](https://github.com/jupyterlab/jupyterlab/pull/4613)) +- Fixed a bug breaking the image viewer upon saving the image. + ([#4602](https://github.com/jupyterlab/jupyterlab/pull/4602)) +- Fixed the font size for code blocks in notebook Markdown headers. + ([#4617](https://github.com/jupyterlab/jupyterlab/pull/4617)) +- Prevented a memory leak when repeatedly rendering a Vega chart. + ([#4904](https://github.com/jupyterlab/jupyterlab/pull/4904)) +- Support dropped terminal connection re-connecting. + ([#4763](https://github.com/jupyterlab/jupyterlab/issues/4763), + [#4802](https://github.com/jupyterlab/jupyterlab/pull/4802)) +- Use `require.ensure` in `vega4-extension` to lazily load + `vega-embed` and its dependencies on first render. + ([#4706](https://github.com/jupyterlab/jupyterlab/pull/4706)) +- Relative links to documents that include anchor tags will now + correctly scroll the document to the right place. + ([#4692](https://github.com/jupyterlab/jupyterlab/pull/4692)) +- Fix default settings JSON in setting editor. + ([#4591](https://github.com/jupyterlab/jupyterlab/issues/4591), + [#4595](https://github.com/jupyterlab/jupyterlab/pull/4595)) +- Fix setting editor pane layout's stretch factor. + ([#2971](https://github.com/jupyterlab/jupyterlab/issues/2971), + [#4772](https://github.com/jupyterlab/jupyterlab/pull/4772)) +- Programmatically set settings are now output with nicer formatting. + ([#4870](https://github.com/jupyterlab/jupyterlab/pull/4870)) +- Fixed a bug in displaying one-line CSV files. + ([#4795](https://github.com/jupyterlab/jupyterlab/issues/4795), + [#4796](https://github.com/jupyterlab/jupyterlab/pull/4796)) +- Fixed a bug where JSON arrays in rich outputs were collapsed into + strings. + ([#4480](https://github.com/jupyterlab/jupyterlab/pull/4480)) + +## [Beta 2 (v0.32.0)](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.32.0) + +### Apr 16, 2018 + +This is the second in the JupyterLab Beta series of releases. It +contains many enhancements, bugfixes, and refinements, including: + +- Better handling of a corrupted or invalid state database. + ([#3619](https://github.com/jupyterlab/jupyterlab/issues/3619), + [#3622](https://github.com/jupyterlab/jupyterlab/issues/3622), + [#3687](https://github.com/jupyterlab/jupyterlab/issues/3687), + [#4114](https://github.com/jupyterlab/jupyterlab/issues/4114)). +- Fixing file dirty status indicator. + ([#3652](https://github.com/jupyterlab/jupyterlab/issues/3652)). +- New option for whether to autosave documents. + ([#3734](https://github.com/jupyterlab/jupyterlab/issues/3734)). +- More commands in the notebook context menu. + ([#3770](https://github.com/jupyterlab/jupyterlab/issues/3770), + [#3909](https://github.com/jupyterlab/jupyterlab/issues/3909)) +- Defensively checking for completion metadata from kernels. + ([#3888](https://github.com/jupyterlab/jupyterlab/issues/3888)) +- New "Shutdown all" button in the Running panel. + ([#3764](https://github.com/jupyterlab/jupyterlab/issues/3764)) +- Performance improvements wherein non-focused documents poll the + server less. + ([#3931](https://github.com/jupyterlab/jupyterlab/issues/3931)) +- Changing the keyboard shortcut for singled-document-mode to + something less easy to trigger. + ([#3889](https://github.com/jupyterlab/jupyterlab/issues/3889)) +- Performance improvements for rendering text streams, especially + around progress bars. + ([#4045](https://github.com/jupyterlab/jupyterlab/issues/4045)). +- Canceling a "Restart Kernel" now functions correctly. + ([#3703](https://github.com/jupyterlab/jupyterlab/issues/3703)). +- Defer loading file contents until after the application has been + restored. + ([#4087](https://github.com/jupyterlab/jupyterlab/issues/4087)). +- Ability to rotate, flip, and invert images in the image viewer. + ([#4000](https://github.com/jupyterlab/jupyterlab/issues/4000)) +- Major performance improvements for large CSV viewing. + ([#3997](https://github.com/jupyterlab/jupyterlab/issues/3997)). +- Always show the context menu in the file browser, even for an empty + directory. + ([#4264](https://github.com/jupyterlab/jupyterlab/issues/4264)). +- 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)). +- 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)). +- 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) + +### Jan 11, 2018 + +- Add a `/tree` handler and `Copy Shareable Link` to file listing + right click menu: + +- Experimental support for saved workspaces: + [#3490](https://github.com/jupyterlab/jupyterlab/issues/3490), + [#3586](https://github.com/jupyterlab/jupyterlab/issues/3586) +- Added types information to the completer: + [#3508](https://github.com/jupyterlab/jupyterlab/issues/3508) +- More improvements to the top level menus: + +- Editor settings for notebook cells: + +- Simplification of theme extensions: + +- New CSS variable naming scheme: + +- Improvements to cell selection and dragging: + +- Style and typography improvements: + + + + + + + + +## [v0.30.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.30.0) + +### Dec 05, 2017 + +- Semantic menus: +- Settings editor now allows comments and provides setting validation: + +- Switch to Yarn as the package manager: + +- Support for carriage return in outputs: + [#2761](https://github.com/jupyterlab/jupyterlab/issues/2761) +- Upgrade to TypeScript 2.6: + +- Cleanup of the build, packaging, and extension systems. + `jupyter labextension install` is now the recommended way to install + a local directory. Local directories are considered linked to the + application. cf +- `--core-mode` and `--dev-mode` are now semantically different. + `--core-mode` is a version of JupyterLab using released JavaScript + packages and is what we ship in the Python package. `--dev-mode` is + 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) + +### Nov 17, 2017 + +Bug fix for file browser right click handling. + + +## [v0.29.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.29.0) + +### Nov 09, 2017 + +- Create new view of cell in cell context menu. + [#3159](https://github.com/jupyterlab/jupyterlab/issues/3159) +- New Renderers for VDOM and JSON mime types and files. + [#3157](https://github.com/jupyterlab/jupyterlab/issues/3157) +- Switch to React for our VDOM implementation. Affects the + `VDomRenderer` class. + [#3133](https://github.com/jupyterlab/jupyterlab/issues/3133) +- Standalone Cell Example. + [#3155](https://github.com/jupyterlab/jupyterlab/issues/3155) + +## [v0.28.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.28.0) + +### Oct 16, 2017 + +This release generally focuses on developer and extension author +enhancements and general bug fixes. + +- Plugin id and schema file conventions change. + . +- Theme authoring conventions change. + [#3061](https://github.com/jupyterlab/jupyterlab/issues/3061) +- Enhancements to enabling and disabling of extensions. + [#3078](https://github.com/jupyterlab/jupyterlab/issues/3078) +- Mime extensions API change (`name` -\> `id` and new naming + convention). + [#3078](https://github.com/jupyterlab/jupyterlab/issues/3078) +- Added a `jupyter lab --watch` mode for extension authors. + [#3077](https://github.com/jupyterlab/jupyterlab/issues/3077) +- New comprehensive extension authoring tutorial. + [#2921](https://github.com/jupyterlab/jupyterlab/issues/2921) +- Added the ability to use an alternate LaTeX renderer. + [#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) + +### Aug 23, 2017 + +- Added support for dynamic theme loading. + +- Added an application splash screen. + +- Enhancements to the settings editor. + +- Added a PDF viewer. + [#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) + +### Jul 21, 2017 + +- Implemented server side handling of users settings: + +- Revamped the handling of file types in the application \* affects + document and mime renderers: + +- Updated dialog API \* uses virtual DOM instead of raw DOM nodes and + better use of the widget lifecycle: + + +## [v0.25.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.25.0) + +### Jul 07, 2017 + +- Added a new extension type for mime renderers, with the + `vega2-extension` as a built-in example. Also overhauled the + rendermime interfaces. + + + +- Finished JSON-schema based settings system, using client-side + storage for now. + +- Overhauled the launcher design. + + +- Numerous bug fixes and style updates. + +## [v0.24.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.24.0) + +### Jun 16, 2017 + +- Overhaul of the launcher. + [#2380](https://github.com/jupyterlab/jupyterlab/issues/2380) +- Initial implementation of client-side settings system. + [#2157](https://github.com/jupyterlab/jupyterlab/issues/2157) +- Updatable outputs. + [#2439](https://github.com/jupyterlab/jupyterlab/issues/2439) +- Use new Phosphor Datagrid for CSV viewer. + [#2433](https://github.com/jupyterlab/jupyterlab/issues/2433) +- Added ability to enable/disable extensions without rebuilding. + [#2409](https://github.com/jupyterlab/jupyterlab/issues/2409) +- Added language and tab settings for the file viewer. + [#2406](https://github.com/jupyterlab/jupyterlab/issues/2406) +- Improvements to real time collaboration experience. + [#2387](https://github.com/jupyterlab/jupyterlab/issues/2387) + [#2333](https://github.com/jupyterlab/jupyterlab/issues/2333) +- Compatibility checking for extensions. + [#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) + +### Jun 02, 2017 + +- Chat box feature. + +- Collaborative cursors. + +- Added concept of Drive to ContentsManager. + +- Refactored to enable switching the theme. + +- Clean up the APIs around kernel execution. + +- Various bug fixes and style improvements. + +## [v0.22.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.22.0) + +### May 18, 2017 + +- Export To... for notebooks. + +- Change kernel by clicking on the kernel name in the notebook. + +- Improved handling of running code in text editors. + +- Can select file in file browser by typing: + +- Ability to open a console for a notebook. + +- Upgrade to Phosphor 1.2 with Command Palette fuzzy matching + improvements. + [#1182](https://github.com/jupyterlab/jupyterlab/issues/1182) +- Rename of widgets that had `Widget` in the name and associated + package names. +- New `jupyter labhub` command to launch JupyterLab on JupyterHub: + +- Removed the `utils` from `@jupyterlab/services` in favor of + `PageConfig` and `ServerConnection`. + + +- Cleanup, bug fixes, and style updates. + +## [v0.20.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.20.0) + +### Apr 21, 2017 + +Release Notes: + +- Overhaul of extension handling, see updated docs for + [users](https://github.com/jupyterlab/jupyterlab/blob/dd83a2e4be8bf23c610c163afe4b480215514764/tutorial/extensions_user.md) + and + [developers](https://github.com/jupyterlab/jupyterlab/blob/dd83a2e4be8bf23c610c163afe4b480215514764/tutorial/extensions_dev.md). + +- Added single document mode and a `Tabs` sidebar. + +- More work toward real time collaboration \* implemented a model + database interface that can be in-memory by real time backends. + + +Numerous bug fixes and improvements. + +## [v0.19.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.19.0) + +### Apr 04, 2017 + +Mainly backend-focused release with compatibility with Phosphor 1.0 and +a big refactor of session handling (the ClientSession class) that +provides a simpler object for classes like notebooks, consoles, +inspectors, etc. to use to communicate with the API. Also includes +improvements to the development workflow of JupyterLab itself after the +big split. + + + + +## [v0.18.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.18.0) + +### Mar 21, 2017 + +- Split the repository into multiple packages that are managed using + the lerna build tool. + +- Added restoration of main area layout on refresh. + +- Numerous bug fixes and style updates. + +## [v0.17.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.17.0) + +### Mar 01, 2017 + +- Upgrade to new `@phosphor` packages \* brings a new Command Palette + interaction that should be more intuitive, and restores the ability + to drag to dock panel edges + . +- Refactor of `RenderMime` and associated renders to use live models. + See and + . +- Improvements and bug fixes for the completer widget: + +- Upgrade CodeMirror to 5.23: + +- Numerous style updates and bug fixes. + +## [v0.16.0](https://github.com/jupyterlab/jupyterlab/releases/tag/v0.16.0) + +### Feb 09, 2017 + +- Adds a Cell Tools sidebar that allows you to edit notebook cell + metadata. + [#1586](https://github.com/jupyterlab/jupyterlab/issues/1586). +- Adds keyboard shortcuts to switch between tabs (Cmd/Ctrl LeftArrow + and Cmd/Ctrl RightArrow). + [#1647](https://github.com/jupyterlab/jupyterlab/issues/1647) +- Upgrades to xterm.js 2.3. + [#1664](https://github.com/jupyterlab/jupyterlab/issues/1664) +- Fixes a bug in application config, but lab extensions will need to + be re-enabled. + [#1607](https://github.com/jupyterlab/jupyterlab/issues/1607) +- Numerous other bug fixes and style improvements. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b315733..51ee26a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,8 @@ -# Contributing to ElixirNote +# Contributing to JupyterLab 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.3.x/developer/contributing.html) or +[Read the Docs](https://jupyterlab.readthedocs.io/en/latest/developer/contributing.html) or [Repo docs](docs/source/developer/contributing.rst) (for the latest). diff --git a/Dockerfile b/Dockerfile index cf33c3b..ab929fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + FROM mambaorg/micromamba:0.14.0 as build # Install basic tools @@ -6,7 +9,7 @@ RUN micromamba install -qy -c conda-forge python nodejs yarn \ && chown jovyan $HOME # Install npm packages - faster build thanks to caching -## package_json.tar.gz contains all package.json files using +## 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 @@ -45,4 +48,4 @@ COPY ./docker/jupyter_server_config.json /etc/jupyter/ EXPOSE 8888 -ENTRYPOINT ["jupyter", "lab"] +ENTRYPOINT ["elixir-lab"] diff --git a/LICENSE b/LICENSE index 4d67eb3..882b961 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2022 Project ElixirNote 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 d804fad..0000000 --- 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 fe53373..9c8b522 100644 --- a/README.md +++ b/README.md @@ -1,171 +1,89 @@ +
+ badge +
- logo -
+ logo
- A Better Data Science Notebook + Analyze data any time, anywhere
# ElixirNote -[![Downloads](https://pepy.tech/badge/jupyterlab/month)](https://pepy.tech/project/jupyterlab/month) [![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) [![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) - -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) - -![architecture](/jupyterlab/staging/assets/architecture.jpg) - -[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 -via [PyPI](https://pypi.org/search/?q=jupyterlab&o=-created&c=Framework+%3A%3A+Jupyter), -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 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.3.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. - -Read the current JupyterLab documentation on [ReadTheDocs](http://jupyterlab.readthedocs.io/en/stable/). - ---- - -## Getting started - -### Installation - -Project installation instructions from the git sources are available in the [contributor documentation](CONTRIBUTING.md). - -### pip - -If you use `pip`, you can install it with: - -```shell -git clone git@github.com:ElixirNote/elixirnote.git -cd elixirnote -pip install -e . -jlpm install -jlpm run build # Build the dev mode assets (optional) -jlpm run build:core # Build the core mode assets (optional) -jupyter lab build # Build the app dir assets (optional) -``` - -### Running - -Start up JupyterLab using: - -```bash -jupyter lab --dev-mode --watch --allow-root --no-browser --ip=0.0.0.0 -``` - -JupyterLab will open automatically in the browser. See the [documentation](http://jupyterlab.readthedocs.io/en/3.3.x/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. - -### Prerequisites and Supported Browsers -The latest versions of the following browsers are currently _known to work_: - -- Firefox -- Chrome -- Safari - -See our [documentation](http://jupyterlab.readthedocs.io/en/3.3.x/getting_started/installation.html) for additional details. - ---- - -## Getting help - -We encourage you to ask questions on the [Discourse forum](https://discourse.jupyter.org/c/jupyterlab). A question answered there can become a useful resource for others. - -### Bug report - -To report a bug please read the [guidelines](https://jupyterlab.readthedocs.io/en/3.3.x/getting_started/issue.html) and then open a [Github issue](https://github.com/jupyterlab/jupyterlab/issues/new?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 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). - ---- +[ElixirNote](https://github.com/ElixirNote/elixirnote/tags) is a next-generation web-based user interface for +Project Jupyter. The Commercial product such as [Hex](https://hex.tech/), [Deepnote](https://deepnote.com/) ... are also good choices. + +![ecosystem](https://raw.githubusercontent.com/ElixirNote/.github/main/profile/elixir-ecosystem-v3.svg) + +Read the current ElixirNote documentation on [ElixirNote Docs](https://ciusji.gitbook.io/elixirnote/). + +## Main Features + +- **A new way to notebook** + - Use SQL, Python, and Julia together, or alone + - No-code visualization + - A magic, reactive execution model + - Advanced version control +- **Publish work as interactive data apps** + - A full library of UI components + - Drag-and-drop layouts + - Instant publishing + - Live commenting +- **Build organizational knowledge** + - Discovery work in the knowledge library + - Organize with categories and statuses +- **Security first** + - Single tenant / private VPC deploys + - HIPAA compliant, and BAA friendly + - SSO support through Google, Okta, Keycloak, and more + +## Documentation + +- [Get Started](https://ciusji.gitbook.io/elixirnote/guides/get-started) +- [Installation](https://ciusji.gitbook.io/elixirnote/guides/installation) +- [Interface Overview](https://ciusji.gitbook.io/elixirnote/guides/interface-overview) +- [Working With Files](https://ciusji.gitbook.io/elixirnote/guides/working-with-files) +- [Text Editor](https://ciusji.gitbook.io/elixirnote/guides/text-editor) +- [Notebooks](https://ciusji.gitbook.io/elixirnote/guides/notebooks) +- [Terminals](https://ciusji.gitbook.io/elixirnote/guides/terminals) +- [Command Palette](https://ciusji.gitbook.io/elixirnote/guides/command-palette) +- [File & Output Format](https://ciusji.gitbook.io/elixirnote/guides/file-and-output-formats) +- [Extensions](https://ciusji.gitbook.io/elixirnote/guides/extensions) +- [Built-in Services](https://ciusji.gitbook.io/elixirnote/guides/built-in-services) +- [Elixir Hub](https://ciusji.gitbook.io/elixirnote/guides/elixirnote-hub) +- [Realtime Collaboration](https://ciusji.gitbook.io/elixirnote/guides/real-time-collaboration) +- [APIs](https://ciusji.gitbook.io/elixirnote/guides/apis) +- [FAQs](https://ciusji.gitbook.io/elixirnote/appendix/faqs) + +## Getting Help + +We encourage you to ask questions on the [discussion forum](https://github.com/orgs/ElixirNote/discussions). A question answered there can become a useful resource for others. + +## Bug Report + +To report a bug please read the [guidelines](https://github.com/ElixirNote/elixirnote/issues) and then open a [Github issue](https://github.com/ElixirNote/elixirnote/issues). 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 related discussion is still needed after an issue is locked, please open a new issue and reference the old issue. ## Development -### Extending JupyterLab +### Extending ElixirNote -To start developing an extension for JupyterLab, see the [developer documentation](https://jupyterlab.readthedocs.io/en/3.3.x/extension/extension_dev.html) and the [API docs](https://jupyterlab.readthedocs.io/en/3.3.x/api/). +To start developing an extension for ElixirNote, see the [developer documentation](https://ciusji.gitbook.io/elixirnote/guides/extensions) and the [API docs](https://ciusji.gitbook.io/elixirnote/guides/apis). ### Contributing -To contribute code or documentation to JupyterLab itself, please read the [contributor documentation](https://jupyterlab.readthedocs.io/en/3.3.x/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.3.x/LICENSE). - -### Team - -JupyterLab is part of [Project Jupyter](http://jupyter.org/) and is developed by an open community. The maintenance team is assisted by a much larger group of contributors to JupyterLab and Project Jupyter as a whole. - -JupyterLab's current maintainers are listed in alphabetical order, with affiliation, and main areas of contribution: - -- Mehmet Bektas, Splunk (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, - 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). -- 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, - prolific contributions throughout the code base). -- Jeremy Tuloup, QuantStack (general development, extensions). - -Maintainer emeritus: - -- Chris Colbert, Project Jupyter (co-creator, application/low-level architecture, - technical leadership, vision, PhosphorJS) -- Jessica Forde, Project Jupyter (demo, documentation) -- Tim George, Cal Poly (UI/UX design, strategy, management, user needs analysis). -- Cameron Oelsen, Cal Poly (UI/UX design). -- Ian Rose, Quansight/City of LA (general core development, extensions). -- Andrew Schlaepfer, Bloomberg (general development, extensions). -- Saul Shanabrook, Quansight (general development, extensions) - -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. +To contribute code or documentation to ElixirNote itself, please read the [contributor documentation](https://github.com/ElixirNote/elixirnote/blob/main/CONTRIBUTING.md). ---- +ElixirNote follows the Jupyter [Community Guides](https://jupyter.readthedocs.io/en/latest/community/content-community.html) 🌈. -### Weekly Dev Meeting +## License -We have videoconference meetings every week where we discuss what we have been working on and get feedback from one another. +ElixirNote 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/ElixirNote/elixirnote/blob/main/LICENSE). -Anyone is welcome to attend, if they would like to discuss a topic or just to listen in. +license -- When: Wednesdays [9AM Pacific Time](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) diff --git a/binder/jupyter_notebook_config.py b/binder/jupyter_notebook_config.py index f876014..f6ddf9e 100644 --- a/binder/jupyter_notebook_config.py +++ b/binder/jupyter_notebook_config.py @@ -1,58 +1,62 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + common = [ - '--no-browser', - '--debug', - '--port={port}', - '--ServerApp.ip=127.0.0.1', + "--no-browser", + "--debug", + "--port={port}", + "--ServerApp.ip=127.0.0.1", '--ServerApp.token=""', # Disable dns rebinding protection here, since our 'Host' header # is not going to be localhost when coming from hub.mybinder.org - '--ServerApp.allow_remote_access=True' + "--ServerApp.allow_remote_access=True", ] -lab_command = ' '.join([ - 'jupyter', - 'lab', - '--dev-mode', - '--extensions-in-dev-mode', - '--collaborative', - '--ServerApp.base_url={base_url}lab-dev', -] + common + ['>jupyterlab-dev.log 2>&1']) - - -lab_splice_command = ' '.join([ - 'jupyter', - 'lab', - 'build', - '--splice-source', - '--minimize=False', - '--dev-build=True', - '--debug', - '>jupyterlab-spliced.log 2>&1', - '&&', - 'jupyter', - 'lab', - '--ServerApp.base_url={base_url}lab-spliced', -] + common + ['>jupyterlab-spliced.log 2>&1']) +lab_command = " ".join( + [ + "jupyter", + "lab", + "--dev-mode", + "--extensions-in-dev-mode", + "--collaborative", + "--ServerApp.base_url={base_url}lab-dev", + ] + + common + + [">jupyterlab-dev.log 2>&1"] +) + + +lab_splice_command = " ".join( + [ + "jupyter", + "lab", + "build", + "--splice-source", + "--minimize=False", + "--dev-build=True", + "--debug", + ">jupyterlab-spliced.log 2>&1", + "&&", + "jupyter", + "lab", + "--ServerApp.base_url={base_url}lab-spliced", + ] + + common + + [">jupyterlab-spliced.log 2>&1"] +) c.ServerProxy.servers = { - 'lab-dev': { - 'command': [ - '/bin/bash', '-c', lab_command - ], - 'timeout': 60, - 'absolute_url': True + "lab-dev": {"command": ["/bin/bash", "-c", lab_command], "timeout": 60, "absolute_url": True}, + "lab-spliced": { + "command": ["/bin/bash", "-c", lab_splice_command], + "timeout": 300, + "absolute_url": True, }, - 'lab-spliced': { - 'command': [ - '/bin/bash', '-c', lab_splice_command - ], - 'timeout': 300, - 'absolute_url': True - } } -c.NotebookApp.default_url = '/lab-dev' +c.NotebookApp.default_url = "/lab-dev" import logging + c.NotebookApp.log_level = logging.DEBUG diff --git a/binder/postBuild b/binder/postBuild index 1b7738c..b299832 100755 --- a/binder/postBuild +++ b/binder/postBuild @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -pip install -e . +pip install -e .[dev] jlpm diff --git a/binder/start b/binder/start index 067b064..defdcb7 100755 --- a/binder/start +++ b/binder/start @@ -3,10 +3,10 @@ import sys import shutil import os -argv = sys.argv[1:] + ['--config', 'binder/jupyter_notebook_config.py'] +argv = sys.argv[1:] + ["--config", "binder/jupyter_notebook_config.py"] print(argv) -with open('startup_args.txt', 'w') as fid: +with open("startup_args.txt", "w") as fid: fid.write(str(argv)) os.execv(shutil.which(argv[0]), argv) diff --git a/buildapi.py b/buildapi.py new file mode 100644 index 0000000..7f7e4f8 --- /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"]) + py_version = py_version.decode("utf-8").strip() + + if Version(npm_version) != Version(py_version): + raise ValueError("Version mismatch, please run `npm run prepare:python-release`") diff --git a/builder/package.json b/builder/package.json index 9939285..c146aea 100644 --- a/builder/package.json +++ b/builder/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/builder", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Extension Builder", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -33,40 +33,37 @@ "watch": "tsc -w --listEmittedFiles" }, "dependencies": { - "@jupyterlab/buildutils": "^3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/application": "^1.16.0", - "@lumino/commands": "^1.12.0", - "@lumino/coreutils": "^1.5.3", - "@lumino/disposable": "^1.4.3", - "@lumino/domutils": "^1.2.3", - "@lumino/dragdrop": "^1.7.1", - "@lumino/messaging": "^1.4.3", - "@lumino/properties": "^1.2.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/buildutils": "^4.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/application": "^1.29.0", + "@lumino/commands": "^1.20.0", + "@lumino/coreutils": "^1.12.0", + "@lumino/disposable": "^1.10.1", + "@lumino/domutils": "^1.8.1", + "@lumino/dragdrop": "^1.14.0", + "@lumino/messaging": "^1.10.1", + "@lumino/properties": "^1.8.1", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "ajv": "^6.12.3", "commander": "~6.0.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", "glob": "~7.1.6", "license-webpack-plugin": "^2.3.14", "mini-css-extract-plugin": "~1.3.2", + "mini-svg-data-uri": "^1.4.4", "path-browserify": "^1.0.0", "process": "^0.11.10", - "raw-loader": "~4.0.0", - "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", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", + "webpack-merge": "^5.8.0", "worker-loader": "^3.0.2" }, "devDependencies": { @@ -75,7 +72,7 @@ "@types/node": "^14.6.1", "@types/supports-color": "^5.3.0", "rimraf": "~3.0.0", - "typescript": "~4.1.3" + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/builder/src/build.ts b/builder/src/build.ts index 6a0ec77..4e3bf36 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'; @@ -209,11 +210,14 @@ export namespace Build { }, { 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 9eaae24..897d28d 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 0b0db09..540521b 100644 --- a/builder/src/extensionConfig.ts +++ b/builder/src/extensionConfig.ts @@ -263,7 +263,7 @@ function generateConfig({ publicPath: staticUrl || 'auto' }, module: { - rules: [{ test: /\.html$/, use: 'file-loader' }] + rules: [{ test: /\.html$/, type: 'asset/resource' }] }, plugins }, @@ -273,7 +273,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 62c4e14..321acb2 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 e110f8c..68634ca 100644 --- a/builder/src/webpack.config.base.ts +++ b/builder/src/webpack.config.base.ts @@ -3,39 +3,34 @@ 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: /\.txt$/, type: 'asset/source' }, + { 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/resource' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/font-woff' + type: 'asset/resource' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=application/octet-stream' + type: 'asset/resource' }, - { 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', + generator: { + dataUrl: (content: any) => miniSVGDataURI(content.toString()) } }, { @@ -43,9 +38,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$/, @@ -104,6 +97,7 @@ module.exports = { fallback: { url: false, buffer: false, + crypto: false, // See https://github.com/webpack/webpack/blob/3471c776059ac2d26593ea39f9c47c1874253dbb/lib/ModuleNotFoundError.js#L13-L42 path: require.resolve('path-browserify'), process: require.resolve('process/browser') diff --git a/buildutils/package.json b/buildutils/package.json index 53e87cf..7758246 100644 --- a/buildutils/package.json +++ b/buildutils/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/buildutils", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Build Utilities", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -34,13 +34,12 @@ "verdaccio.yml" ], "scripts": { - "build": "tsc", + "build": "tsc && cd template && npm run build", "build:all": "npm run build", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "watch": "tsc -w --listEmittedFiles" }, "dependencies": { - "@lumino/coreutils": "^1.5.3", "@yarnpkg/lockfile": "^1.1.0", "child_process": "~1.0.2", "commander": "~6.0.0", @@ -51,20 +50,20 @@ "inquirer": "^7.1.0", "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.1.1" + "sort-package-json": "~1.53.1", + "typescript": "~4.7.3", + "verdaccio": "^5.13.3" }, "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/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 68d8884..0000000 --- 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 656a582..1e9bfc2 100644 --- a/buildutils/src/bump-js-major.ts +++ b/buildutils/src/bump-js-major.ts @@ -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(); diff --git a/buildutils/src/bumpversion.ts b/buildutils/src/bumpversion.ts index ed9dbee..501b5a9 100644 --- a/buildutils/src/bumpversion.ts +++ b/buildutils/src/bumpversion.ts @@ -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(); @@ -62,18 +62,6 @@ commander 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); - - return; - } - // Determine the version spec to use for lerna. let lernaVersion = 'preminor'; if (spec === 'build') { @@ -104,10 +92,10 @@ commander }, true ); - // For a preminor release, we bump 10 minor versions so that we do + // 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); } diff --git a/buildutils/src/clean-packages.ts b/buildutils/src/clean-packages.ts index 27cf480..026f927 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-theme.ts b/buildutils/src/create-theme.ts deleted file mode 100644 index c27829c..0000000 --- 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/ensure-package.ts b/buildutils/src/ensure-package.ts index 91e3498..767ff92 100644 --- a/buildutils/src/ensure-package.ts +++ b/buildutils/src/ensure-package.ts @@ -332,9 +332,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); } @@ -463,13 +460,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); @@ -545,7 +550,8 @@ export async function ensurePackage( const buildScript = data.scripts?.build || ''; if ( buildScript && - (pkgPath.indexOf('packages') == -1 || buildScript.indexOf('tsc') == -1) && + ((pkgPath.indexOf('packages') == -1 && pkgPath.indexOf('template') == -1) || + buildScript.indexOf('tsc') == -1) && !isPrivate ) { data.scripts['build:all'] = 'npm run build'; @@ -689,7 +695,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'); diff --git a/buildutils/src/ensure-repo.ts b/buildutils/src/ensure-repo.ts index 04bab24..e7fbd8e 100644 --- a/buildutils/src/ensure-repo.ts +++ b/buildutils/src/ensure-repo.ts @@ -24,6 +24,8 @@ import { type Dict = { [key: string]: T }; +type CoreData = Map; + // URL config for this branch // Source and target branches // Target RTD version name @@ -33,16 +35,16 @@ type Dict = { [key: string]: T }; // Master should target latest // All other release branches should target a specific named version const URL_CONFIG = { - source: '3.2.x', - target: '3.3.x', - rtdVersion: '3.3.x' + source: 'master', + target: 'master', + rtdVersion: 'latest' }; // Data to ignore. const MISSING: Dict = { '@jupyterlab/coreutils': ['path'], '@jupyterlab/buildutils': ['path', 'webpack'], - '@jupyterlab/builder': ['path', 'crypto'], + '@jupyterlab/builder': ['path'], '@jupyterlab/galata': ['fs', 'path'], '@jupyterlab/testutils': ['fs', 'path'], '@jupyterlab/vega5-extension': ['vega-embed'] @@ -50,7 +52,7 @@ const MISSING: Dict = { 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': [ @@ -72,34 +74,45 @@ const UNUSED: Dict = { '@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' ], '@jupyterlab/buildutils': ['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' + ], '@jupyterlab/coreutils': ['path-browserify'], + '@jupyterlab/fileeditor': ['regexp-match-indices'], '@jupyterlab/galata': ['node-fetch', 'http-server'], '@jupyterlab/services': ['node-fetch', 'ws'], '@jupyterlab/rendermime': ['@jupyterlab/mathjax2'], '@jupyterlab/testutils': [ + 'fs-extra', 'node-fetch', 'identity-obj-proxy', 'jest-raw-loader', - 'markdown-loader-jest', 'jest-junit', 'jest-summary-reporter' ], '@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 @@ -122,9 +135,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 @@ -136,12 +147,12 @@ const SKIP_CSS: Dict = { '@jupyterlab/codeeditor', '@jupyterlab/codemirror', '@jupyterlab/fileeditor', - '@jupyterlab/notebook', - 'codemirror' + '@jupyterlab/notebook' ], '@jupyterlab/filebrowser': ['@jupyterlab/statusbar'], '@jupyterlab/fileeditor': ['@jupyterlab/statusbar'], '@jupyterlab/help-extension': ['@jupyterlab/application'], + '@jupyterlab/lsp': ['codemirror'], '@jupyterlab/metapackage': [ '@jupyterlab/ui-components', '@jupyterlab/apputils', @@ -162,6 +173,8 @@ const SKIP_CSS: Dict = { '@jupyterlab/outputarea', '@jupyterlab/cells', '@jupyterlab/notebook', + '@jupyterlab/cell-toolbar', + '@jupyterlab/cell-toolbar-extension', '@jupyterlab/celltags', '@jupyterlab/celltags-extension', '@jupyterlab/fileeditor', @@ -173,6 +186,7 @@ const SKIP_CSS: Dict = { '@jupyterlab/console-extension', '@jupyterlab/csvviewer', '@jupyterlab/documentsearch', + '@jupyterlab/docprovider', '@jupyterlab/csvviewer-extension', '@jupyterlab/debugger', '@jupyterlab/debugger-extension', @@ -196,9 +210,12 @@ 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/markedparser-extension', '@jupyterlab/mathjax2', '@jupyterlab/mathjax2-extension', '@jupyterlab/nbconvert-css', @@ -221,6 +238,8 @@ 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' @@ -243,8 +262,7 @@ const SKIP_CSS: Dict = { '@jupyterlab/theme-dark-extension': [ '@jupyterlab/application', '@jupyterlab/apputils' - ], - '@jupyterlab/ui-extension': ['@blueprintjs/icons'] + ] }; const pkgData: Dict = {}; @@ -403,27 +421,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 { @@ -432,8 +460,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')) && @@ -479,7 +505,66 @@ 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); + corePackage.jupyterlab.mimeExtensions = {}; + + const coreData = getCoreData(corePaths); coreData.forEach((data, name) => { // Determine if the package wishes to be included in the top-level // dependencies. @@ -497,7 +582,7 @@ function ensureJupyterlab(): string[] { // Handle extensions. ['extension', 'mimeExtension'].forEach(item => { - let ext = meta[item]; + let ext = data.jupyterlab[item]; if (ext === true) { ext = ''; } @@ -508,6 +593,7 @@ function ensureJupyterlab(): string[] { }); }); + corePackage.jupyterlab.linkedPackages = {}; utils.getLernaPaths().forEach(pkgPath => { const dataPath = path.join(pkgPath, 'package.json'); let data: any; @@ -528,6 +614,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']; @@ -558,6 +648,37 @@ 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. */ @@ -707,6 +828,12 @@ 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); @@ -726,7 +853,7 @@ export async function ensureIntegrity(): Promise { .getCorePaths() .filter(pth => !tsConfigDocExclude.some(pkg => pth.includes(pkg))) .map(pth => { - return { path: './' + path.relative('.', pth).replace('\\/g', '/') }; + return { path: './' + path.relative('.', pth).replace(/\\/g, '/') }; }); utils.writeJSONFile(tsConfigdocPath, tsConfigdocData); @@ -754,6 +881,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) { @@ -781,5 +914,8 @@ export async function ensureIntegrity(): Promise { } if (require.main === module) { - void ensureIntegrity(); + void ensureIntegrity().catch(e => { + process.exitCode = 1; + console.error(e); + }); } diff --git a/buildutils/src/local-repository.ts b/buildutils/src/local-repository.ts index a29839a..5cfba0c 100644 --- a/buildutils/src/local-repository.ts +++ b/buildutils/src/local-repository.ts @@ -1,3 +1,9 @@ +/* + * 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'; @@ -33,10 +39,10 @@ async function startLocalRegistry(out_dir: string, port = DEFAULT_PORT) { } catch (e) { // Do nothing } - if (!prev_npm || prev_npm.indexOf('localhost') !== -1) { + if (!prev_npm || prev_npm.indexOf('0.0.0.0') !== -1) { prev_npm = 'https://registry.npmjs.org/'; } - if (prev_yarn.indexOf('localhost') !== -1) { + if (prev_yarn.indexOf('0.0.0.0') !== -1) { prev_yarn = ''; } @@ -50,6 +56,7 @@ auth: uplinks: npmjs: url: ${prev_npm} + timeout: 10m packages: '@*/*': access: $all @@ -66,7 +73,7 @@ packages: const log_file = path.join(out_dir, 'verdaccio.log'); // Start local registry - const args = `-c verdaccio.yml -l localhost:${port}`; + const args = `-c verdaccio.yml -l 0.0.0.0:${port}`; console.log(`Starting verdaccio on port ${port} in ${out_dir}`); // Ensure a clean log file @@ -119,10 +126,20 @@ packages: utils.writeJSONFile(info_file, data); // Set registry to local registry - const local_registry = `http://localhost:${port}`; - child_process.execSync(`npm config set registry "${local_registry}"`); + const local_registry = `http://0.0.0.0:${port}`; + child_process.execFileSync('npm', [ + 'config', + 'set', + 'registry', + local_registry + ]); try { - child_process.execSync(`yarn config set registry "${local_registry}"`); + child_process.execFileSync('yarn', [ + 'config', + 'set', + 'registry', + local_registry + ]); } catch (e) { // yarn not available } @@ -141,25 +158,26 @@ packages: loginPs.stdout.on('data', (chunk: string) => { const data = Buffer.from(chunk, 'utf-8').toString().trim(); console.log('stdout:', data); - switch (data) { - case 'Username:': - console.log('Passing username...'); - loginPs.stdin.write(user + '\n'); - break; - case 'Password:': - console.log('Passing password...'); - loginPs.stdin.write(pass + '\n'); - break; - case 'Email: (this IS public)': - console.log('Passing email...'); - loginPs.stdin.write(email + '\n'); - break; - default: - reject(`Unexpected prompt: "${data}"`); - } if (data.indexOf('Logged in as') !== -1) { loginPs.stdin.end(); // do not accept here yet, the token may not have been written + } else { + switch (data) { + case 'Username:': + console.log('Passing username...'); + loginPs.stdin.write(user + '\n'); + break; + case 'Password:': + console.log('Passing password...'); + loginPs.stdin.write(pass + '\n'); + break; + case 'Email: (this IS public)': + console.log('Passing email...'); + loginPs.stdin.write(email + '\n'); + break; + default: + reject(`Unexpected prompt: "${data}"`); + } } loginPs.stderr.on('data', (chunk: string) => { const data = Buffer.from(chunk, 'utf-8').toString().trim(); @@ -235,7 +253,7 @@ function fixLinks(package_dir: string) { let hash = shasum.update(content); console.log('Prior hash', hash.digest('hex')); - const regex = /http\:\/\/localhost\:\d+/g; + const regex = /http\:\/\/0\.0\.0\.0\:\d+/g; const new_content = content.replace(regex, yarn_reg); shasum = crypto.createHash('sha256'); @@ -271,7 +289,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); }); @@ -280,7 +298,7 @@ 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); }); @@ -289,7 +307,7 @@ program .command('fix-links') .option('--path ', 'Path to the directory with a yarn lock') .action((options: any) => { - utils.exitOnUuncaughtException(); + utils.exitOnUncaughtException(); fixLinks(options.path || process.cwd()); }); @@ -297,7 +315,7 @@ 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 a4b5f73..57ffa78 --- a/buildutils/src/patch-release.ts +++ b/buildutils/src/patch-release.ts @@ -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(); diff --git a/buildutils/src/prepare-python-release.ts b/buildutils/src/prepare-python-release.ts index 458e607..b47ed84 100644 --- a/buildutils/src/prepare-python-release.ts +++ b/buildutils/src/prepare-python-release.ts @@ -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 8ccb6f3..19d54cf 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 388a2d9..0000000 --- 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 3237841..5b5d804 100644 --- a/buildutils/src/publish.ts +++ b/buildutils/src/publish.ts @@ -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 6f8d125..0000000 --- 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-dist-tag.ts b/buildutils/src/update-dist-tag.ts old mode 100755 new mode 100644 diff --git a/buildutils/src/utils.ts b/buildutils/src/utils.ts index 6534b96..b274b37 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'; + +const assert = require('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) { console.error('Uncaught exception', err); process.exit(1); @@ -70,7 +77,7 @@ export function getCorePaths(): string[] { */ 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'); @@ -95,7 +102,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' @@ -117,11 +127,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; } /** @@ -185,7 +199,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]; } @@ -227,14 +241,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) { @@ -320,6 +327,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`. * @@ -333,12 +359,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 index 82a1db6..a22ddb4 100644 --- a/buildutils/src/yarnlock.d.ts +++ b/buildutils/src/yarnlock.d.ts @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + declare module '@yarnpkg/lockfile'; diff --git a/buildutils/template/.vscode/launch.json b/buildutils/template/.vscode/launch.json new file mode 100644 index 0000000..64126e4 --- /dev/null +++ b/buildutils/template/.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/buildutils/template/babel.config.js b/buildutils/template/babel.config.js index 8b5c764..bf69a46 100644 --- a/buildutils/template/babel.config.js +++ b/buildutils/template/babel.config.js @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + module.exports = require('@jupyterlab/testutils/lib/babel.config'); diff --git a/buildutils/template/jest.config.js b/buildutils/template/jest.config.js index 178440a..64773dc 100644 --- a/buildutils/template/jest.config.js +++ b/buildutils/template/jest.config.js @@ -1,2 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const func = require('@jupyterlab/testutils/lib/jest-config'); module.exports = func(__dirname); diff --git a/buildutils/template/package.json b/buildutils/template/package.json index 70e34fc..1b5a1e1 100644 --- a/buildutils/template/package.json +++ b/buildutils/template/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/template", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Package Template", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -27,7 +27,6 @@ ], "scripts": { "build": "tsc -b", - "build:all": "npm run build", "build:test": "tsc --build tsconfig.test.json", "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo", "test": "jest", @@ -37,12 +36,12 @@ "watch": "tsc -b --watch" }, "devDependencies": { - "@jupyterlab/testutils": "^3.3.2", + "@jupyterlab/testutils": "^4.0.0-alpha.12", "@types/jest": "^26.0.10", "jest": "^26.4.2", "rimraf": "~3.0.0", "ts-jest": "^26.3.0", - "typescript": "~4.1.3" + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/clean.py b/clean.py index 3f2da8a..76b8117 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 @@ -5,38 +8,32 @@ # Workaround for https://github.com/git-for-windows/git/issues/607 -if os.name == 'nt': - for (root, dnames, files) in os.walk(here): - if 'node_modules' in dnames: - subprocess.check_call(['rmdir', '/s', '/q', 'node_modules'], - cwd=root, shell=True) - dnames.remove('node_modules') +if os.name == "nt": + for (root, dnames, _) in os.walk(here): + if "node_modules" in dnames: + subprocess.check_call(["rmdir", "/s", "/q", "node_modules"], cwd=root, shell=True) + 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) def resolvePattern(pat): - """handle a leading `#` or `@` in a pattern - """ + """handle a leading `#` or `@` in a pattern""" pat = pat.strip() - if not pat or pat.startswith('#'): + if not pat or pat.startswith("#"): return [] - elif pat.startswith('@'): + elif pat.startswith("@"): raw = pat[1:] - return [ - raw, - f'!packages/**/{raw}', - f'!**/node_modules/**/{raw}' - ] + return [raw, f"!packages/**/{raw}", f"!**/node_modules/**/{raw}"] else: return [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)] +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_command = ['git', 'clean', '-dfx'] + git_clean_exclude +git_clean_command = ["git", "clean", "-dfx"] + git_clean_exclude subprocess.check_call(git_clean_command, cwd=here) diff --git a/conftest.py b/conftest.py index 88e3f63..780004c 100644 --- a/conftest.py +++ b/conftest.py @@ -5,25 +5,22 @@ import pytest - pytest_plugins = [ "jupyter_server.pytest_plugin", "jupyterlab_server.pytest_plugin", - "jupyterlab.pytest_plugin" + "jupyterlab.pytest_plugin", ] def pytest_addoption(parser): """ - Adds flags for py.test. + Adds flags for pytest. This is called by the pytest API """ group = parser.getgroup("general") - group.addoption('--quick', action='https://github.com/store_true', - help="Skip slow tests") - group.addoption('--slow', action='https://github.com/store_true', - help="Run only slow tests") + group.addoption("--quick", action="https://github.com/store_true", help="Skip slow tests") + group.addoption("--slow", action="https://github.com/store_true", help="Run only slow tests") def pytest_configure(config): diff --git a/design/notebook.md b/design/notebook.md index 6c6edcb..c518504 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 1b6fc69..5a44157 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 c0556d8..2b8b92f 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) { @@ -212,6 +194,7 @@ export async function main() { var devMode = (PageConfig.getOption('devMode') || '').toLowerCase() === 'true'; if (exposeAppInBrowser || devMode) { + // This is deprecated in favor of more generic window.jupyterapp window.jupyterlab = lab; window.jupyterapp = lab; } diff --git a/dev_mode/package.json b/dev_mode/package.json index 815a0db..69589d3 100644 --- a/dev_mode/package.json +++ b/dev_mode/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/application-top", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "license": "BSD-3-Clause", "scripts": { @@ -16,166 +16,176 @@ "watch": "webpack --watch" }, "resolutions": { - "@jupyterlab/application": "~3.3.2", - "@jupyterlab/application-extension": "~3.3.2", - "@jupyterlab/apputils": "~3.3.2", - "@jupyterlab/apputils-extension": "~3.3.2", - "@jupyterlab/attachments": "~3.3.2", - "@jupyterlab/cells": "~3.3.2", - "@jupyterlab/celltags": "~3.3.2", - "@jupyterlab/celltags-extension": "~3.3.2", - "@jupyterlab/codeeditor": "~3.3.2", - "@jupyterlab/codemirror": "~3.3.2", - "@jupyterlab/codemirror-extension": "~3.3.2", - "@jupyterlab/completer": "~3.3.2", - "@jupyterlab/completer-extension": "~3.3.2", - "@jupyterlab/console": "~3.3.2", - "@jupyterlab/console-extension": "~3.3.2", - "@jupyterlab/coreutils": "~5.3.2", - "@jupyterlab/csvviewer": "~3.3.2", - "@jupyterlab/csvviewer-extension": "~3.3.2", - "@jupyterlab/debugger": "~3.3.2", - "@jupyterlab/debugger-extension": "~3.3.2", - "@jupyterlab/docmanager": "~3.3.2", - "@jupyterlab/docmanager-extension": "~3.3.2", - "@jupyterlab/docprovider": "~3.3.2", - "@jupyterlab/docprovider-extension": "~3.3.2", - "@jupyterlab/docregistry": "~3.3.2", - "@jupyterlab/documentsearch": "~3.3.2", - "@jupyterlab/documentsearch-extension": "~3.3.2", - "@jupyterlab/extensionmanager": "~3.3.2", - "@jupyterlab/extensionmanager-extension": "~3.3.2", - "@jupyterlab/filebrowser": "~3.3.2", - "@jupyterlab/filebrowser-extension": "~3.3.2", - "@jupyterlab/fileeditor": "~3.3.2", - "@jupyterlab/fileeditor-extension": "~3.3.2", - "@jupyterlab/help-extension": "~3.3.2", - "@jupyterlab/htmlviewer": "~3.3.2", - "@jupyterlab/htmlviewer-extension": "~3.3.2", - "@jupyterlab/hub-extension": "~3.3.2", - "@jupyterlab/imageviewer": "~3.3.2", - "@jupyterlab/imageviewer-extension": "~3.3.2", - "@jupyterlab/inspector": "~3.3.2", - "@jupyterlab/inspector-extension": "~3.3.2", - "@jupyterlab/javascript-extension": "~3.3.2", - "@jupyterlab/json-extension": "~3.3.2", - "@jupyterlab/launcher": "~3.3.2", - "@jupyterlab/launcher-extension": "~3.3.2", - "@jupyterlab/logconsole": "~3.3.2", - "@jupyterlab/logconsole-extension": "~3.3.2", - "@jupyterlab/mainmenu": "~3.3.2", - "@jupyterlab/mainmenu-extension": "~3.3.2", - "@jupyterlab/markdownviewer": "~3.3.2", - "@jupyterlab/markdownviewer-extension": "~3.3.2", - "@jupyterlab/mathjax2": "~3.3.2", - "@jupyterlab/mathjax2-extension": "~3.3.2", - "@jupyterlab/metapackage": "~3.3.2", - "@jupyterlab/nbconvert-css": "~3.3.2", - "@jupyterlab/nbformat": "~3.3.2", - "@jupyterlab/notebook": "~3.3.2", - "@jupyterlab/notebook-extension": "~3.3.2", - "@jupyterlab/observables": "~4.3.2", - "@jupyterlab/outputarea": "~3.3.2", - "@jupyterlab/pdf-extension": "~3.3.2", - "@jupyterlab/property-inspector": "~3.3.2", - "@jupyterlab/rendermime": "~3.3.2", - "@jupyterlab/rendermime-extension": "~3.3.2", - "@jupyterlab/rendermime-interfaces": "~3.3.2", - "@jupyterlab/running": "~3.3.2", - "@jupyterlab/running-extension": "~3.3.2", - "@jupyterlab/services": "~6.3.2", - "@jupyterlab/settingeditor": "~3.3.2", - "@jupyterlab/settingeditor-extension": "~3.3.2", - "@jupyterlab/settingregistry": "~3.3.2", - "@jupyterlab/shared-models": "~3.3.2", - "@jupyterlab/shortcuts-extension": "~3.3.2", - "@jupyterlab/statedb": "~3.3.2", - "@jupyterlab/statusbar": "~3.3.2", - "@jupyterlab/statusbar-extension": "~3.3.2", - "@jupyterlab/terminal": "~3.3.2", - "@jupyterlab/terminal-extension": "~3.3.2", - "@jupyterlab/theme-dark-extension": "~3.3.2", - "@jupyterlab/theme-light-extension": "~3.3.2", - "@jupyterlab/toc": "~5.3.2", - "@jupyterlab/toc-extension": "~5.3.2", - "@jupyterlab/tooltip": "~3.3.2", - "@jupyterlab/tooltip-extension": "~3.3.2", - "@jupyterlab/translation": "~3.3.2", - "@jupyterlab/translation-extension": "~3.3.2", - "@jupyterlab/ui-components": "~3.3.2", - "@jupyterlab/ui-components-extension": "~3.3.2", - "@jupyterlab/vdom": "~3.3.2", - "@jupyterlab/vdom-extension": "~3.3.2", - "@jupyterlab/vega5-extension": "~3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/application": "^1.16.0", - "@lumino/commands": "^1.12.0", - "@lumino/coreutils": "^1.5.3", - "@lumino/disposable": "^1.4.3", - "@lumino/domutils": "^1.2.3", - "@lumino/dragdrop": "^1.7.1", - "@lumino/messaging": "^1.4.3", - "@lumino/properties": "^1.2.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "~4.0.0-alpha.12", + "@jupyterlab/application-extension": "~4.0.0-alpha.12", + "@jupyterlab/apputils": "~4.0.0-alpha.12", + "@jupyterlab/apputils-extension": "~4.0.0-alpha.12", + "@jupyterlab/attachments": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/cells": "~4.0.0-alpha.12", + "@jupyterlab/celltags": "~4.0.0-alpha.12", + "@jupyterlab/celltags-extension": "~4.0.0-alpha.12", + "@jupyterlab/codeeditor": "~4.0.0-alpha.12", + "@jupyterlab/codemirror": "~4.0.0-alpha.12", + "@jupyterlab/codemirror-extension": "~4.0.0-alpha.12", + "@jupyterlab/collaboration": "~4.0.0-alpha.12", + "@jupyterlab/collaboration-extension": "~4.0.0-alpha.12", + "@jupyterlab/completer": "~4.0.0-alpha.12", + "@jupyterlab/completer-extension": "~4.0.0-alpha.12", + "@jupyterlab/console": "~4.0.0-alpha.12", + "@jupyterlab/console-extension": "~4.0.0-alpha.12", + "@jupyterlab/coreutils": "~6.0.0-alpha.12", + "@jupyterlab/csvviewer": "~4.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/debugger": "~4.0.0-alpha.12", + "@jupyterlab/debugger-extension": "~4.0.0-alpha.12", + "@jupyterlab/docmanager": "~4.0.0-alpha.12", + "@jupyterlab/docmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/docprovider": "~4.0.0-alpha.12", + "@jupyterlab/docprovider-extension": "~4.0.0-alpha.12", + "@jupyterlab/docregistry": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch-extension": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser-extension": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/help-extension": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/hub-extension": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/inspector": "~4.0.0-alpha.12", + "@jupyterlab/inspector-extension": "~4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "~4.0.0-alpha.12", + "@jupyterlab/json-extension": "~4.0.0-alpha.12", + "@jupyterlab/launcher": "~4.0.0-alpha.12", + "@jupyterlab/launcher-extension": "~4.0.0-alpha.12", + "@jupyterlab/logconsole": "~4.0.0-alpha.12", + "@jupyterlab/logconsole-extension": "~4.0.0-alpha.12", + "@jupyterlab/lsp": "~4.0.0-alpha.12", + "@jupyterlab/lsp-extension": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu-extension": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/markedparser-extension": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "~4.0.0-alpha.12", + "@jupyterlab/metapackage": "~4.0.0-alpha.12", + "@jupyterlab/nbconvert-css": "~4.0.0-alpha.12", + "@jupyterlab/nbformat": "~4.0.0-alpha.12", + "@jupyterlab/notebook": "~4.0.0-alpha.12", + "@jupyterlab/notebook-extension": "~4.0.0-alpha.12", + "@jupyterlab/observables": "~5.0.0-alpha.12", + "@jupyterlab/outputarea": "~4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "~4.0.0-alpha.12", + "@jupyterlab/property-inspector": "~4.0.0-alpha.12", + "@jupyterlab/rendermime": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-interfaces": "~3.8.0-alpha.12", + "@jupyterlab/running": "~4.0.0-alpha.12", + "@jupyterlab/running-extension": "~4.0.0-alpha.12", + "@jupyterlab/services": "~7.0.0-alpha.12", + "@jupyterlab/settingeditor": "~4.0.0-alpha.12", + "@jupyterlab/settingeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/settingregistry": "~4.0.0-alpha.12", + "@jupyterlab/shared-models": "~4.0.0-alpha.12", + "@jupyterlab/shortcuts-extension": "~4.0.0-alpha.12", + "@jupyterlab/statedb": "~4.0.0-alpha.12", + "@jupyterlab/statusbar": "~4.0.0-alpha.12", + "@jupyterlab/statusbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/terminal": "~4.0.0-alpha.12", + "@jupyterlab/terminal-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-dark-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "~4.0.0-alpha.12", + "@jupyterlab/toc": "~6.0.0-alpha.12", + "@jupyterlab/toc-extension": "~6.0.0-alpha.12", + "@jupyterlab/tooltip": "~4.0.0-alpha.12", + "@jupyterlab/tooltip-extension": "~4.0.0-alpha.12", + "@jupyterlab/translation": "~4.0.0-alpha.12", + "@jupyterlab/translation-extension": "~4.0.0-alpha.12", + "@jupyterlab/ui-components": "~4.0.0-alpha.27", + "@jupyterlab/ui-components-extension": "~4.0.0-alpha.12", + "@jupyterlab/vdom": "~4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "~4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "~4.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/application": "^1.27.0", + "@lumino/commands": "^1.19.0", + "@lumino/coreutils": "^1.11.1", + "@lumino/disposable": "^1.10.1", + "@lumino/domutils": "^1.8.1", + "@lumino/dragdrop": "^1.13.1", + "@lumino/messaging": "^1.10.1", + "@lumino/properties": "^1.8.1", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "react": "^17.0.1", "react-dom": "^17.0.1", - "yjs": "^13.5.17" + "yjs": "^13.5.34" }, "dependencies": { - "@jupyterlab/application": "~3.3.2", - "@jupyterlab/application-extension": "~3.3.2", - "@jupyterlab/apputils-extension": "~3.3.2", - "@jupyterlab/celltags-extension": "~3.3.2", - "@jupyterlab/codemirror-extension": "~3.3.2", - "@jupyterlab/completer-extension": "~3.3.2", - "@jupyterlab/console-extension": "~3.3.2", - "@jupyterlab/coreutils": "~5.3.2", - "@jupyterlab/csvviewer-extension": "~3.3.2", - "@jupyterlab/debugger-extension": "~3.3.2", - "@jupyterlab/docmanager-extension": "~3.3.2", - "@jupyterlab/docprovider-extension": "~3.3.2", - "@jupyterlab/documentsearch-extension": "~3.3.2", - "@jupyterlab/extensionmanager-extension": "~3.3.2", - "@jupyterlab/filebrowser-extension": "~3.3.2", - "@jupyterlab/fileeditor-extension": "~3.3.2", - "@jupyterlab/help-extension": "~3.3.2", - "@jupyterlab/htmlviewer-extension": "~3.3.2", - "@jupyterlab/hub-extension": "~3.3.2", - "@jupyterlab/imageviewer-extension": "~3.3.2", - "@jupyterlab/inspector-extension": "~3.3.2", - "@jupyterlab/javascript-extension": "~3.3.2", - "@jupyterlab/json-extension": "~3.3.2", - "@jupyterlab/launcher-extension": "~3.3.2", - "@jupyterlab/logconsole-extension": "~3.3.2", - "@jupyterlab/mainmenu-extension": "~3.3.2", - "@jupyterlab/markdownviewer-extension": "~3.3.2", - "@jupyterlab/mathjax2-extension": "~3.3.2", - "@jupyterlab/notebook-extension": "~3.3.2", - "@jupyterlab/pdf-extension": "~3.3.2", - "@jupyterlab/rendermime-extension": "~3.3.2", - "@jupyterlab/running-extension": "~3.3.2", - "@jupyterlab/settingeditor-extension": "~3.3.2", - "@jupyterlab/shortcuts-extension": "~3.3.2", - "@jupyterlab/statusbar-extension": "~3.3.2", - "@jupyterlab/terminal-extension": "~3.3.2", - "@jupyterlab/theme-dark-extension": "~3.3.2", - "@jupyterlab/theme-light-extension": "~3.3.2", - "@jupyterlab/toc-extension": "~5.3.2", - "@jupyterlab/tooltip-extension": "~3.3.2", - "@jupyterlab/translation-extension": "~3.3.2", - "@jupyterlab/ui-components-extension": "~3.3.2", - "@jupyterlab/vdom-extension": "~3.3.2", - "@jupyterlab/vega5-extension": "~3.3.2" + "@jupyterlab/application": "~4.0.0-alpha.12", + "@jupyterlab/application-extension": "~4.0.0-alpha.12", + "@jupyterlab/apputils-extension": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/celltags-extension": "~4.0.0-alpha.12", + "@jupyterlab/codemirror-extension": "~4.0.0-alpha.12", + "@jupyterlab/collaboration-extension": "~4.0.0-alpha.12", + "@jupyterlab/completer-extension": "~4.0.0-alpha.12", + "@jupyterlab/console-extension": "~4.0.0-alpha.12", + "@jupyterlab/coreutils": "~6.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/debugger-extension": "~4.0.0-alpha.12", + "@jupyterlab/docmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/docprovider-extension": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch-extension": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser-extension": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/help-extension": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/hub-extension": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/inspector-extension": "~4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "~4.0.0-alpha.12", + "@jupyterlab/json-extension": "~4.0.0-alpha.12", + "@jupyterlab/launcher-extension": "~4.0.0-alpha.12", + "@jupyterlab/logconsole-extension": "~4.0.0-alpha.12", + "@jupyterlab/lsp-extension": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu-extension": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/markedparser-extension": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "~4.0.0-alpha.12", + "@jupyterlab/notebook-extension": "~4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-extension": "~4.0.0-alpha.12", + "@jupyterlab/running-extension": "~4.0.0-alpha.12", + "@jupyterlab/settingeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/shortcuts-extension": "~4.0.0-alpha.12", + "@jupyterlab/statusbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/terminal-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-dark-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "~4.0.0-alpha.12", + "@jupyterlab/toc-extension": "~6.0.0-alpha.12", + "@jupyterlab/tooltip-extension": "~4.0.0-alpha.12", + "@jupyterlab/translation-extension": "~4.0.0-alpha.12", + "@jupyterlab/ui-components-extension": "~4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "~4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "~4.0.0-alpha.12" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", - "@jupyterlab/buildutils": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", + "@jupyterlab/buildutils": "^4.0.0-alpha.12", "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", "glob": "~7.1.6", "handlebars": "^4.5.3", @@ -183,33 +193,33 @@ "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", + "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", + "style-loader": "~3.3.1", "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", + "webpack": "^5.72.0", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-cli": "^4.9.2", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0", "worker-loader": "^3.0.2", - "yarn-deduplicate": "^2.1.1" + "yarn-deduplicate": "^5.0.0" }, "engines": { "node": ">=12.0.0" }, "jupyterlab": { - "name": "JupyterLab", - "version": "3.3.2", + "name": "ElixirNote", + "version": "4.0.0a30", "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": "", @@ -227,8 +237,10 @@ "@jupyterlab/inspector-extension": "", "@jupyterlab/launcher-extension": "", "@jupyterlab/logconsole-extension": "", + "@jupyterlab/lsp-extension": "", "@jupyterlab/mainmenu-extension": "", "@jupyterlab/markdownviewer-extension": "", + "@jupyterlab/markedparser-extension": "", "@jupyterlab/mathjax2-extension": "", "@jupyterlab/notebook-extension": "", "@jupyterlab/rendermime-extension": "", @@ -251,14 +263,15 @@ "@jupyterlab/pdf-extension": "", "@jupyterlab/vega5-extension": "" }, - "externalExtensions": {}, "buildDir": "./static", "outputDir": ".", "singletonPackages": [ "@jupyterlab/application", "@jupyterlab/apputils", + "@jupyterlab/cell-toolbar", "@jupyterlab/codeeditor", "@jupyterlab/codemirror", + "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", @@ -273,6 +286,7 @@ "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/markdownviewer", "@jupyterlab/notebook", @@ -311,12 +325,16 @@ "@jupyterlab/apputils": "../packages/apputils", "@jupyterlab/apputils-extension": "../packages/apputils-extension", "@jupyterlab/attachments": "../packages/attachments", + "@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", @@ -353,10 +371,13 @@ "@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/markedparser-extension": "../packages/markedparser-extension", "@jupyterlab/mathjax2": "../packages/mathjax2", "@jupyterlab/mathjax2-extension": "../packages/mathjax2-extension", "@jupyterlab/metapackage": "../packages/metapackage", diff --git a/dev_mode/style.js b/dev_mode/style.js index 402784a..f604b47 100644 --- a/dev_mode/style.js +++ b/dev_mode/style.js @@ -3,8 +3,10 @@ import '@jupyterlab/application-extension/style/index.js'; import '@jupyterlab/apputils-extension/style/index.js'; +import '@jupyterlab/cell-toolbar-extension/style/index.js'; import '@jupyterlab/celltags-extension/style/index.js'; import '@jupyterlab/codemirror-extension/style/index.js'; +import '@jupyterlab/collaboration-extension/style/index.js'; import '@jupyterlab/completer-extension/style/index.js'; import '@jupyterlab/console-extension/style/index.js'; import '@jupyterlab/csvviewer-extension/style/index.js'; @@ -24,8 +26,10 @@ 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/markedparser-extension/style/index.js'; import '@jupyterlab/mathjax2-extension/style/index.js'; import '@jupyterlab/notebook-extension/style/index.js'; import '@jupyterlab/pdf-extension/style/index.js'; diff --git a/dev_mode/templates/403.html b/dev_mode/templates/403.html index 3155157..34a495a 100644 --- a/dev_mode/templates/403.html +++ b/dev_mode/templates/403.html @@ -1,3 +1,8 @@ + + diff --git a/dev_mode/templates/error.html b/dev_mode/templates/error.html index 0d59d99..e5fa3df 100644 --- a/dev_mode/templates/error.html +++ b/dev_mode/templates/error.html @@ -8,7 +8,7 @@ - ElixirNote + {% block title %}{{page_title | escape}}{% endblock %} {% block favicon %}{% endblock %} @@ -28,7 +28,7 @@
{% block h1_error %} -

Notebook assets not detected, please rebuild

+

ElixirNote assets not detected, please rebuild

diff --git a/dev_mode/templates/partial.html b/dev_mode/templates/partial.html index a3f368e..3c44af5 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 179ee06..6d17d79 100644 --- a/dev_mode/templates/template.html +++ b/dev_mode/templates/template.html @@ -1,8 +1,13 @@ + + - ElixirNote + <%= htmlWebpackPlugin.options.title %> <%= require('html-loader!./partial.html') %> diff --git a/dev_mode/webpack.config.js b/dev_mode/webpack.config.js index b7a76ec..ceeddc9 100644 --- a/dev_mode/webpack.config.js +++ b/dev_mode/webpack.config.js @@ -1,8 +1,7 @@ -// 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 +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; @@ -21,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 = [ diff --git a/dev_mode/webpack.prod.config.js b/dev_mode/webpack.prod.config.js index a6b08a7..025b532 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 b107e53..f8143bd 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; diff --git a/dev_mode/webpack.prod.release.config.js b/dev_mode/webpack.prod.release.config.js index 1b31286..f48a3e7 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 8d7f39c..bf94e53 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 # diff --git a/docs/assets/elixir-ecosystem-v2.svg b/docs/assets/elixir-ecosystem-v2.svg new file mode 100644 index 0000000..4dda97e --- /dev/null +++ b/docs/assets/elixir-ecosystem-v2.svg @@ -0,0 +1,111 @@ + + + elixir-ecosystem-v2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ElixirNote + + + + + + + Permissions + + + + + + + + Scheduling + + + + + + + + Collaborate + + + + + + + + Visualizations + + + + + + + + Comments + + + + + + + + + + + + diff --git a/docs/assets/elixir-ecosystem.svg b/docs/assets/elixir-ecosystem.svg new file mode 100644 index 0000000..1c79e06 --- /dev/null +++ b/docs/assets/elixir-ecosystem.svg @@ -0,0 +1,122 @@ + + + elixir-ecosystem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/elixirnote-intro.svg b/docs/assets/elixirnote-intro.svg new file mode 100644 index 0000000..0da304b --- /dev/null +++ b/docs/assets/elixirnote-intro.svg @@ -0,0 +1,44 @@ + + + elixirnote-intro + + + + + + + + + + + + + + + + + Go from data to knowledge + + + Powered by GuinsooLab + + + + + ElixirNote + + + + + + + + One Platform + Limitless Possibilities + + + GuinsooLab + + + + diff --git a/docs/assets/elixirnote2.svg b/docs/assets/elixirnote2.svg new file mode 100644 index 0000000..6edffce --- /dev/null +++ b/docs/assets/elixirnote2.svg @@ -0,0 +1,10 @@ + + + elixirnote + + + + + + + diff --git a/docs/assets/guinsoolab-badge.png b/docs/assets/guinsoolab-badge.png new file mode 100644 index 0000000..4822269 Binary files /dev/null and b/docs/assets/guinsoolab-badge.png differ diff --git a/docs/assets/overview-1.png b/docs/assets/overview-1.png new file mode 100644 index 0000000..b5b461a Binary files /dev/null and b/docs/assets/overview-1.png differ diff --git a/docs/assets/overview-2.png b/docs/assets/overview-2.png new file mode 100644 index 0000000..480a153 Binary files /dev/null and b/docs/assets/overview-2.png differ diff --git a/docs/assets/overview-3.png b/docs/assets/overview-3.png new file mode 100644 index 0000000..ee37864 Binary files /dev/null and b/docs/assets/overview-3.png differ diff --git a/docs/assets/overview-4.png b/docs/assets/overview-4.png new file mode 100644 index 0000000..212e9c1 Binary files /dev/null and b/docs/assets/overview-4.png differ diff --git a/docs/environment.yml b/docs/environment.yml deleted file mode 100644 index 57d67b0..0000000 --- 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 -- jsx-lexer -- myst-parser diff --git a/docs/make.bat b/docs/make.bat index c7f53a3..858b453 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/source/_static/css/custom.css b/docs/source/_static/css/custom.css index ef54a5a..1302a49 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -1,22 +1,29 @@ -h4 { - font-size: 100%; +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +/* 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 +34,41 @@ 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 0000000..a65b84f Binary files /dev/null and b/docs/source/_static/logo-icon.png differ diff --git a/docs/source/_static/logo-rectangle.svg b/docs/source/_static/logo-rectangle.svg new file mode 100644 index 0000000..f978b42 --- /dev/null +++ b/docs/source/_static/logo-rectangle.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/docs/source/_templates/breadcrumbs.html b/docs/source/_templates/breadcrumbs.html deleted file mode 100644 index 6bb97b3..0000000 --- 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 0000000..5f2bd71 --- /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 b91bf27..0000000 --- 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 cf6cd3f..b8fb76b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,8 @@ #!/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,13 +24,16 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) -import os -import os.path as osp +import json 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 ------------------------------------------------ @@ -39,57 +45,55 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'myst_parser', - 'sphinx.ext.intersphinx', - 'sphinx.ext.mathjax', - 'sphinx_copybutton' + "myst_parser", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx_copybutton", ] myst_enable_extensions = ["html_image"] myst_heading_anchors = 3 # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The file extensions of source files. # Sphinx considers the files with this suffix as sources. # The value can be a dictionary mapping file extensions to file types. -source_suffix = { - '.rst': 'restructuredtext', - '.md': 'markdown' -} +source_suffix = {".rst": "restructuredtext", ".md": "markdown"} # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'JupyterLab' -copyright = '2018, Project Jupyter' -author = 'Project Jupyter' +project = "JupyterLab" +copyright = f"2018-{time.localtime().tm_year}, Project Jupyter" +author = "Project Jupyter" # The version info for the project you're documenting, acts as replacement for # |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) # The short X.Y version. -version = '%i.%i' % version_ns['version_info'][:2] +version = "{0:d}.{1:d}".format(*version_ns["version_info"]) # The full version, including alpha/beta/rc tags. -release = version_ns['__version__'] +release = version_ns["__version__"] # The language for content autogenerated by Sphinx. Refer to documentation # 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 = None +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. @@ -101,48 +105,117 @@ # 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 / "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}") + print(f"already have {api_index!s}") 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)) + check_call(jlpm + ["build:packages"], cwd=str(root)) + check_call(jlpm + ["docs"], cwd=str(root)) + + dest_dir = out_dir / "api" + print(f"Copying {docs_api!s} -> {dest_dir!s}") + if dest_dir.exists(): + shutil.rmtree(str(dest_dir)) + shutil.copytree(str(docs_api), str(dest_dir)) - 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) # Copy frontend files for snippet inclusion FILES_LIST = [ # File paths should be relative to jupyterlab root folder - 'packages/settingregistry/src/plugin-schema.json' + "packages/settingregistry/src/plugin-schema.json" ] -SNIPPETS_FOLDER = 'snippets' +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 + """ + print(f"\n\n{temp_folder}\n") + 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" + + +def document_commands_list(temp_folder: Path) -> None: + """Generate the command list documentation page for 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) # -- Options for HTML output ---------------------------------------------- @@ -150,20 +223,47 @@ 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", + }, + ], + "use_edit_page_button": True, + "navbar_align": "left", + "navbar_end": ["navbar-icon-links.html", "search-field.html"], + "footer_items": ["copyright.html"], +} # 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, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -171,28 +271,22 @@ 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.3.x", # Version + "github_version": "master", # Version "conf_py_path": "/docs/source/", # Path in the checkout to the docs root } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'JupyterLabdoc' +htmlhelp_basename = "JupyterLabdoc" # -- Options for LaTeX output --------------------------------------------- @@ -201,15 +295,12 @@ def copy_code_files(temp_folder): # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -219,8 +310,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", + ), ] @@ -228,10 +324,7 @@ def copy_code_files(temp_folder): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'jupyterlab', 'JupyterLab Documentation', - [author], 1) -] +man_pages = [(master_doc, "jupyterlab", "JupyterLab Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -240,13 +333,18 @@ def copy_code_files(temp_folder): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'JupyterLab', 'JupyterLab Documentation', - author, 'JupyterLab', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "JupyterLab", + "JupyterLab Documentation", + author, + "JupyterLab", + "One line description of project.", + "Miscellaneous", + ), ] - # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. @@ -265,27 +363,35 @@ def copy_code_files(temp_folder): # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - +epub_exclude_files = ["search.html"] # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = {"https://docs.python.org/": None} def setup(app): - dest = osp.join(HERE, 'getting_started/changelog.md') - shutil.copy(osp.join(HERE, '..', '..', 'CHANGELOG.md'), dest) - app.add_css_file('css/custom.css') # may also be an URL - build_api_docs(app.outdir) - - copy_code_files(osp.join(app.srcdir, SNIPPETS_FOLDER)) - - def clean_code_files(app, exception): + 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 + # Skip we are dealing with internationalization + outdir = Path(app.outdir) + if outdir.name != "gettext": + build_api_docs(outdir) + + copy_code_files(Path(app.srcdir) / SNIPPETS_FOLDER) + tmp_files = copy_automated_screenshots(Path(app.srcdir) / IMAGES_FOLDER) + + def clean_code_files(tmp_files, app, exception): """Remove temporary folder.""" try: - shutil.rmtree(osp.join(app.srcdir, SNIPPETS_FOLDER)) + shutil.rmtree(str(Path(app.srcdir) / SNIPPETS_FOLDER)) except Exception as e: print(f"Fail to remove temporary snippet folder: {e}") - - app.connect('build-finished', clean_code_files) \ No newline at end of file + + for f in tmp_files: + f.unlink() + + document_commands_list(Path(app.srcdir)) + + app.connect("build-finished", partial(clean_code_files, tmp_files)) diff --git a/docs/source/developer/api.rst b/docs/source/developer/api.rst index 126e9e1..e2b0937 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 3b8bce1..f543f77 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 2684873..04a7fc2 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 @@ -29,6 +32,16 @@ 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 + internationalization + css + api + .. contents:: Table of contents :local: :depth: 1 @@ -42,19 +55,47 @@ Documentation `__. +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. +All JupyterLab v2 users are strongly advised to upgrade as soon as possible. + 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 @@ -65,18 +106,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 (= ``master``) 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 @@ -88,7 +140,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 @@ -97,24 +149,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**: @@ -130,7 +182,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. @@ -139,9 +191,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. @@ -152,15 +204,15 @@ 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. @@ -177,9 +229,20 @@ 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. + +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 master branch and your changes within the browser as well. We recommend you have at least 8 GB of RAM for this. @@ -202,13 +265,22 @@ 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 ``engines`` specification in -`dev_mode/package.json `__. +`dev_mode/package.json `__. If you use ``conda``, you can get it with: .. code:: bash - conda install -c conda-forge 'nodejs' + 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: @@ -225,16 +297,20 @@ To check which version of Node.js is installed: node -v -Installing JupyterLab ---------------------- +Using automation to set up a local development environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you use ``conda``, you may also want to install ``nb_conda_kernels`` to have a kernel -option for different `conda -environments `__ +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. -.. code:: bash +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). - conda install -c conda-forge nb_conda_kernels +A practical example can be found `there `_ and +includes a ``Vagrantfile``, the bootstrap files and additional documentation. + +Installing JupyterLab +--------------------- Fork the JupyterLab `repository `__. @@ -245,11 +321,19 @@ 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) - jlpm run build:core # Build the core mode assets (optional) - jupyter lab build # Build the app dir assets (optional) + +Additionally, you might want to execute the following optional commands: + +.. code:: bash + + # Build the core mode assets (optional) + jlpm run build:core + + # Build the app dir assets (optional) + jupyter lab build Notes: @@ -263,15 +347,15 @@ 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 + 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`. - The ``jlpm`` command is a JupyterLab-provided, locked version of the - `yarn `__ package manager. If you have + `yarn `__ package manager. If you have ``yarn`` installed already, you can use the ``yarn`` command when developing, and it will use the local version of ``yarn`` in ``jupyterlab/yarn.js`` when run in the repository or a built @@ -357,7 +441,7 @@ 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 ``it.only`` to a specific test when debugging. All of the ``test*`` scripts in each package accept ``jest`` `cli -options `__. +options `__. VSCode Debugging """""""""""""""" @@ -408,257 +492,105 @@ 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: - -.. code:: bash +- Approved PR review +- PR review that contains the sentence ``please run benchmark`` - jupyter lab --dev --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``: +- ``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. -.. code:: bash +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``. - go get github.com/tylertreat/comcast +Benchmark parameters +^^^^^^^^^^^^^^^^^^^^ -Then, before you run Lighthouse, enable the throttling (this requires -sudo): +The benchmark can be customized using the following environment variables: -.. 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. - run lighthouse:throttling:start - -This enables the "WIFI (good)" preset of comcast, which should emulate -loading JupyterLab over a local network. - -Then run the lighthouse tests: - -.. 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 - - 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**: - If your code change is introducing an update to UI which causes existing UI Tests to fail, then you will need to update reference image(s) for the failing tests. In order to do that, simply go to GitHub Actions page for the failed test and download test artifacts. It will contain test captures in directory ``test/screenshots``. You can copy the capture for the failed test and paste into reference screenshots directory in JupyterLab source code, replacing the failing test's reference capture. Reference captures are located in ``ui-tests/reference-output/screenshots`` in JupyterLab source code. + If your code change is introducing an update to UI which causes existing UI Tests to + fail, then you will need to update reference image(s) for the failing tests. In order + to do that, you can post a comment on your PR with the following content: -For more information on UI Testing, please read the `UI Testing developer documentation `__ and `Galata documentation `__. + - ``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 `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 -------------------------------------- @@ -675,6 +607,7 @@ The Debugger Adapter Protocol The following diagram illustrates the types of messages sent between the JupyterLab extension and the kernel. .. image:: ./debugger_protocol_diagram.png + :alt: UML sequence diagram illustrating the interaction between a user, JupyterLab, and the kernel. From top to bottom, the timeline starts with opening the notebook and includes annotations where the debugger is started and stopped. Specific interactions and message types are discussed in the subsequent text. Inspecting Debug Messages in VS Code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -684,6 +617,7 @@ Inspecting the debug messages in VS Code can be useful to understand when debug The first step is to create a test file and a debug configuration (``launch.json``): .. image:: ./debugger_launch_configuration.png + :alt: An editor showing the menu for creating a debug configuration. .. code:: json @@ -704,6 +638,7 @@ The first step is to create a test file and a debug configuration (``launch.json Then start the debugger: .. image:: ./debugger_vscode_start.png + :alt: A started debugging session in the editor. There are additional buttons in the upper right for navigating the session. The content of the log file looks like this: @@ -827,22 +762,18 @@ 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: .. code:: bash - py.test --check-links -k .md . || py.test --check-links -k .md --lf . + python -m pytest --check-links -k .md . || python -m pytest --check-links -k .md --lf . The Read the Docs pages can be built using ``make``: @@ -860,17 +791,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 @@ -882,36 +813,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. -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. +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. + +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 @@ -927,19 +878,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 @@ -1075,6 +1023,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 d646fc1..fe30877 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 04b0aeb..c04b986 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,7 +12,7 @@ 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 @@ -19,7 +22,7 @@ Four elements are used to handle the internationalization of JupyterLab: 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 +And finally it publishes them. All those actions are carried out using helpers defined in ``jupyterlab-translate`` and the cookiecutter 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 ^^^^^^^^^^^^^^^^^^^^^ @@ -100,17 +105,18 @@ There is one optional setting: - The new version in form *X.Y.postZ* - if not provided, the post number will be bumped. .. image:: prep_language_packs.png + :alt: The "Prepare language packs for release" workflow on GitHub Actions. The workflow is: -1. Trigger the manual *Prepare language packs for release* workflow +1. Trigger the manual *Prepare language packs for release* workflow 2. That workflow will open a new pull request with the changes to the language packs 3. The validation workflow `Check language packs version `_ 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. @@ -135,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 d01edfe..8965eeb 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/repo.rst b/docs/source/developer/repo.rst index fccac73..33007d4 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. @@ -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 55e7f4d..c961f43 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 @@ -37,8 +40,8 @@ Models contain an instance of `ModelDB <../api/classes/observables.modeldb-1.htm 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. You can find all the documentation of Yjs `here `_. +`Yjs `_, a high-performance CRDT for building collaborative applications +that automatically sync. At the moment, models contain both a ``ModelDB`` and a ``Shared Model`` instance, so it is possible to access ``ModelDB`` yet. diff --git a/docs/source/extension/extension_dev.rst b/docs/source/extension/extension_dev.rst index cb8b009..90cbba2 100644 --- a/docs/source/extension/extension_dev.rst +++ b/docs/source/extension/extension_dev.rst @@ -1,12 +1,30 @@ +.. 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. + +.. toctree:: + :maxdepth: 1 + + extension_points + ui_components + documents + notebook + virtualdom + ui_helpers + internationalization + extension_tutorial + extension_migration + Other resources --------------- @@ -37,7 +55,7 @@ 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 @@ -156,7 +174,7 @@ A mime renderer plugin is an object with the fields listed in the `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. @@ -171,11 +189,11 @@ 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('https://github.com/images/foo.png')`` or ``url('https://github.com/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. @@ -186,7 +204,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. +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:: @@ -257,10 +275,10 @@ 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``. @@ -503,7 +521,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: @@ -569,7 +587,56 @@ 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``. + +.. 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: @@ -650,24 +717,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 @@ -688,10 +737,7 @@ Testing your extension 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 diff --git a/docs/source/extension/extension_migration.rst b/docs/source/extension/extension_migration.rst index baef190..da1f723 100644 --- a/docs/source/extension/extension_migration.rst +++ b/docs/source/extension/extension_migration.rst @@ -1,12 +1,125 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + .. _extension_migration: Extension Migration Guide ================================================ -JupyterLab 3.0 to 3.1 +JupyterLab 3.x to 4.x --------------------- -Following semver rules, API are compatible. +.. 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. + +API breaking changes +^^^^^^^^^^^^^^^^^^^^ + +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. +- ``@jupyterlab/apputils`` from 3.x to 4.x + Rename ``IToolbarWidgetRegistry.registerFactory`` to ``IToolbarWidgetRegistry.addFactory`` +- ``@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 `Theme Cookiecutter `_ 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`` +- ``@jupyterlab/completer`` from 3.x to 4.x + Major version bumped following the removal of ``ICompletionManager`` token and the replacement + of ``ICompletableAttributes`` interface by ``ICompletionProvider``. To create a completer provider + for JupyterLab, users need to implement the interface ``ICompletionProvider`` and then register + this provider with ``ICompletionProviderManager`` token. +- ``@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/docmanager`` from 3.x to 4.x + The ``renameDialog`` now receives the ``DocumentRegistry.Context`` instead of a path. +- ``@jupyterlab/docprovider`` from 3.x to 4.x + ``WebSocketProviderWithLocks`` has been renamed to ``WebSocketProvider``. + ``acquireLock``, ``releaseLock``, ``requestInitialContent`` and ``putInitializedState`` have been removed from ``IDocumentProvider``. + ``renameAck`` is not optional anymore in ``IDocumentProvider``. +- ``@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/fileeditor`` from 3.x to 4.x + Remove the class ``FileEditorCodeWrapper``, instead, you can use ``CodeEditorWrapper`` from ``@jupyterlab/codeeditor``. +- ``@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/notebook`` from 3.x to 4.x + * 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``. +- ``@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``. +- ``@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/shared-models`` from 3.x to 4.x + The ``createCellFromType`` function has been renamed to ``createCellModelFromSharedType`` +- ``@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``. +- ``@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. +- TypeScript 4.7 update + As a result of the update to TypeScript 4.7, 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``. + +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. + +JupyterLab 3.0 to 3.1 +--------------------- New main and context menus customization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,13 +127,14 @@ 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:: @@ -41,13 +155,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. @@ -192,7 +306,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. @@ -313,7 +427,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 @@ -348,6 +462,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 9edf21e..563f8bf 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: @@ -63,7 +66,7 @@ might want to use the services in your extensions. - ``@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 +- ``@jupyterlab/completer:ICompletionProviderManager``: 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 @@ -109,6 +112,7 @@ might want to use the services in your extensions. 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/rendermime:IMarkdownParser``: A service for rendering markdown syntax as HTML content. - ``@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. @@ -125,6 +129,11 @@ might want to use the services in your extensions. 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. @@ -178,7 +187,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, @@ -256,19 +265,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 @@ -300,7 +308,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: @@ -401,7 +409,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, @@ -421,6 +429,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 arguemnts of ``my-command-1`` and ``my-command-2`` in ``args`` +of ``apputils:run-all-enabled`` command as ``args`` list. Launcher -------- @@ -459,6 +492,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 ^^^^^^^^^^^^^^^^ @@ -565,6 +614,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`` @@ -575,15 +627,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 @@ -604,7 +655,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: @@ -730,9 +781,14 @@ When the ``labStatus`` busy state changes, we update the text content of the Toolbar Registry ---------------- -JupyterLab provides an infrastructure to define and customize toolbar widgets of ``DocumentWidget`` s +JupyterLab provides an infrastructure to define and customize toolbar widgets from the settings, which is similar to that defining the context menu and the main menu -bar. A typical example is the notebook toolbar as in the snippet below: +bar. + +Document Widgets +^^^^^^^^^^^^^^^^ + +A typical example is the notebook toolbar as in the snippet below: .. code:: typescript @@ -746,20 +802,20 @@ bar. 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( @@ -773,7 +829,7 @@ bar. A typical example is the notebook toolbar as in the snippet below: ); } } - + const factory = new NotebookWidgetFactory({ name: FACTORY, fileTypes: ['notebook'], @@ -785,19 +841,21 @@ bar. 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 }, @@ -850,16 +908,70 @@ providing a different rank or adding ``"disabled": true`` to remove the item). The current widget factories supporting the toolbar customization are: - ``Notebook``: Notebook panel toolbar +- ``Cell``: Cell toolbar - ``Editor``: Text editor toolbar - ``HTML Viewer``: HTML Viewer toolbar - ``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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The logic detailed in the previous section can be used to customize any widgets with a toolbar. + +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 a toolbar on a widget: + +.. code:: typescript + + function activatePlugin( + app: JupyterFrontEnd, + // ... + toolbarRegistry: IToolbarWidgetRegistry, + settingRegistry: ISettingRegistry + ): void { + + const browser = new FileBrowser(); + + // Toolbar + // - Define a custom toolbar item + toolbarRegistry.registerFactory( + 'FileBrowser', // Factory name + 'uploader', + (browser: FileBrowser) => + new Uploader({ model: browser.model, translator }) + ); + + // - Link the widget toolbar and its definition from the settings + setToolbar( + 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: diff --git a/docs/source/extension/extension_tutorial.rst b/docs/source/extension/extension_tutorial.rst index 4308df0..ccf2be3 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 @@ -81,7 +84,7 @@ 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. @@ -208,7 +211,7 @@ 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: Leave the terminal running the ``jupyter lab`` command open and running JupyterLab to see the effects of changes below. @@ -806,30 +809,43 @@ entire list of import statements looks like the following: 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: 4 + :emphasize-lines: 5 const extension: JupyterFrontEndPlugin = { id: 'jupyterlab_apod', autoStart: true, - requires: [ICommandPalette, ILayoutRestorer], + requires: [ICommandPalette], + optional: [ILayoutRestorer], activate: activate }; +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`` make it a nice to have, and enable your extension to be loaded +in more JupyterLab based applications. + +.. note:: + + You can learn more about ``requires`` and ``optional`` in the :ref:`tokens` section + of the Extension Developer Guide. + 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 - function activate(app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer) { + function activate(app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer | null) { console.log('JupyterLab extension jupyterlab_apod is activated!'); // Declare a widget variable @@ -871,10 +887,12 @@ Finally, rewrite the ``activate`` function so that it: let tracker = new WidgetTracker>({ namespace: 'apod' }); - restorer.restore(tracker, { - command, - name: () => 'apod' - }); + if (restorer) { + restorer.restore(tracker, { + command, + name: () => 'apod' + }); + } } Rebuild your extension one last time and refresh your browser tab. 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 0000000..f92beb9 --- /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 0000000..4ad71cf --- /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 0000000..611b94e --- /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 74a9d30..d0718ac 100644 --- a/docs/source/extension/internationalization.rst +++ b/docs/source/extension/internationalization.rst @@ -1,10 +1,13 @@ +.. Copyright (c) Jupyter Development Team. +.. Distributed under the terms of the Modified BSD License. + Internationalization and Localization ===================================== To internationalize your extension, the following tasks are required: .. note:: - + Please read carefully the :ref:`internationalization-rules` as they are strong constraints for internationalization to work. 1. Add the token ``ITranslator`` from ``@jupyterlab/translation`` package to your plugin dependencies. @@ -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: @@ -47,8 +50,38 @@ You could also look at the following pull requests on the 4. Create and publish the translation for your extension. There are two options: you can either add your extension to the JupyterLab `language packs `_ -or you can create a python package to distribute your extension translation (see `test example `_). +or you can create a python package to distribute your extension translation (see below). + +Create translation python package +--------------------------------- + +Jupyter Lab follows Gettext's approach for translation. Gettext extracts strings from source code, and compiles them with provided translation. This `article `_ briefly explains how Gettext works. + +By using `jupyterlab-translate `_, you can extract, update, and compile your translation. + +After that, you must include your compiled translation (.json, .mo) to your python package. This can be done by editing these two files. + +setup.py: + +.. code:: python + from setuptools import setup + + setup( + # ... + entry_points={"jupyterlab.locale": ["jupyterlab_some_package = jupyterlab_some_package"]}, + ) + + +MANIFEST.in: + +.. code:: text + + recursive-include jupyterlab_some_package *.json + recursive-include jupyterlab_some_package *.mo + +.. note:: + An example is available in the `server test `_ Settings translation -------------------- diff --git a/docs/source/extension/notebook.rst b/docs/source/extension/notebook.rst index 7c60fe3..7bee25d 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 ======== @@ -126,6 +129,37 @@ list. An OutputArea uses a notebook-specific `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 +188,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 @@ -199,9 +233,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'; @@ -285,14 +317,13 @@ Run the following commands: 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 diff --git a/docs/source/extension/ui_components.rst b/docs/source/extension/ui_components.rst index d7abb9e..7261963 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 + @@ -6,10 +11,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/app/webpack.config.js b/examples/app/webpack.config.js index a66c433..e7bee8f 100644 --- a/examples/app/webpack.config.js +++ b/examples/app/webpack.config.js @@ -3,6 +3,7 @@ const data = require('./package.json'); const webpack = require('webpack'); const Build = require('@jupyterlab/builder').Build; +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. @@ -24,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()) } }, { @@ -55,16 +56,12 @@ 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: () => '/' } }) diff --git a/examples/cell/main.py b/examples/cell/main.py index 9b00975..89b9fe2 100644 --- a/examples/cell/main.py +++ b/examples/cell/main.py @@ -11,32 +11,28 @@ run ``python main.py``. """ -import os import json +import os -from jupyterlab_server import LabServerApp from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin, ExtensionHandlerJinjaMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerJinjaMixin, + ExtensionHandlerMixin, +) from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp HERE = os.path.dirname(__file__) -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] + def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] -class ExampleHandler( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, - JupyterHandler - ): + +class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): """Handle requests between the main app page and notebook server.""" def get(self): @@ -44,46 +40,43 @@ def get(self): config_data = { # Use camelCase here, since that's what the lab components expect "appVersion": version, - 'baseUrl': self.base_url, - 'token': self.settings['token'], - 'fullStaticUrl': ujoin(self.base_url, 'static', self.name), - 'frontendUrl': ujoin(self.base_url, 'example/'), + "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', + "index.html", static=self.static_url, base_url=self.base_url, - token=self.settings['token'], - page_config=config_data - ) + token=self.settings["token"], + page_config=config_data, ) + ) class ExampleApp(LabServerApp): - extension_url = '/example' - default_url = '/example' + extension_url = "/example" + default_url = "/example" app_url = "/example" name = __name__ load_other_extensions = False - app_name = 'JupyterLab Example Cell' - static_dir = os.path.join(HERE, 'build') - templates_dir = os.path.join(HERE, 'templates') + app_name = "JupyterLab Example Cell" + static_dir = os.path.join(HERE, "build") + templates_dir = os.path.join(HERE, "templates") app_version = version - 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') + 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) - ) + """Add example handler to Lab Server's handler list.""" + self.handlers.append(("/example", ExampleHandler)) -if __name__ == '__main__': +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/cell/package.json b/examples/cell/package.json index ad6c879..a7b8112 100644 --- a/examples/cell/package.json +++ b/examples/cell/package.json @@ -1,39 +1,35 @@ { "name": "@jupyterlab/example-cell", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/cells": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/completer": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/rendermime": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/commands": "^1.12.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/cells": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/completer": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/rendermime": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/commands": "^1.20.0", + "@lumino/widgets": "^1.33.0", "es6-promise": "~4.2.8" }, "devDependencies": { - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.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": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", "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 d05db0a..245787c --- a/examples/cell/src/index.ts +++ b/examples/cell/src/index.ts @@ -13,7 +13,8 @@ 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 } from '@jupyterlab/apputils'; +import { Toolbar } from '@jupyterlab/ui-components'; import { CodeCell, CodeCellModel } from '@jupyterlab/cells'; @@ -23,7 +24,8 @@ import { Completer, CompleterModel, CompletionHandler, - KernelConnector + ConnectorProxy, + KernelCompleterProvider } from '@jupyterlab/completer'; import { @@ -89,14 +91,23 @@ 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 timeout = 1000; + const provider = new KernelCompleterProvider(); + const connector = new ConnectorProxy( + { widget: cellWidget, editor, session: sessionContext.session }, + [provider], + timeout + ); const handler = new CompletionHandler({ completer, connector }); //sessionContext.session?.kernel. void sessionContext.ready.then(() => { - handler.connector = new KernelConnector({ - session: sessionContext.session - }); + const provider = new KernelCompleterProvider(); + handler.connector = new ConnectorProxy( + { widget: cellWidget, editor, session: sessionContext.session }, + [provider], + timeout + ); }); // Set the handler's editor. @@ -109,10 +120,13 @@ 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', + AppToolbar.createInterruptButton(sessionContext) + ); + toolbar.addItem('restart', AppToolbar.createRestartButton(sessionContext)); + toolbar.addItem('name', AppToolbar.createKernelNameItem(sessionContext)); + 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 ed2bdc7..a839607 100644 --- a/examples/cell/templates/index.html +++ b/examples/cell/templates/index.html @@ -1,3 +1,8 @@ + + @@ -7,10 +12,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 9f54b0f..ab43706 100644 --- a/examples/cell/webpack.config.js +++ b/examples/cell/webpack.config.js @@ -1,4 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], @@ -12,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()) } }, { @@ -29,20 +35,16 @@ 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: () => '/' } }) diff --git a/examples/chrome-example-test.js b/examples/chrome-example-test.js deleted file mode 100644 index ca89bb1..0000000 --- a/examples/chrome-example-test.js +++ /dev/null @@ -1,76 +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 inspect = require('util').inspect; -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(); - if (msg.type() === 'error') { - 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(); - - const html = await page.content(); - if (inspect(html).indexOf('jupyter-config-data') === -1) { - console.error('Error loading JupyterLab page:'); - console.error(html); - } - 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/main.py b/examples/console/main.py index 8e06f01..eef04ce 100644 --- a/examples/console/main.py +++ b/examples/console/main.py @@ -11,79 +11,71 @@ run ``python main.py``. """ -import os import json +import os -from jupyterlab_server import LabServerApp from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin, ExtensionHandlerJinjaMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerJinjaMixin, + ExtensionHandlerMixin, +) from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp HERE = os.path.dirname(__file__) -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] -class ExampleHandler( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, - JupyterHandler - ): +class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): """Handle requests between the main app page and notebook server.""" def get(self): config_data = { # Use camelCase here, since that's what the lab components expect "appVersion": version, - 'baseUrl': self.base_url, - 'token': self.settings['token'], - 'fullStaticUrl': ujoin(self.base_url, 'static', self.name), - 'frontendUrl': ujoin(self.base_url, 'example/'), + "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', + "index.html", static=self.static_url, base_url=self.base_url, - token=self.settings['token'], - page_config=config_data - ) + token=self.settings["token"], + page_config=config_data, ) + ) class ExampleApp(LabServerApp): - extension_url = '/example' - default_url = '/example' + extension_url = "/example" + default_url = "/example" app_url = "/example" load_other_extensions = False name = __name__ - app_name = 'JupyterLab Example Console' - app_settings_dir = os.path.join(HERE, 'build', 'application_settings') - schemas_dir = os.path.join(HERE, 'build', 'schemas') - static_dir = os.path.join(HERE, 'build') - templates_dir = os.path.join(HERE, 'templates') - 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') + app_name = "JupyterLab Example Console" + app_settings_dir = os.path.join(HERE, "build", "application_settings") + schemas_dir = os.path.join(HERE, "build", "schemas") + static_dir = os.path.join(HERE, "build") + templates_dir = os.path.join(HERE, "templates") + 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): """Initialize JupyterLab handlers.""" super().initialize_handlers() - self.handlers.append( - ('/example', ExampleHandler) - ) + self.handlers.append(("/example", ExampleHandler)) -if __name__ == '__main__': +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/console/package.json b/examples/console/package.json index 5db4a13..a6c28c1 100644 --- a/examples/console/package.json +++ b/examples/console/package.json @@ -1,37 +1,32 @@ { "name": "@jupyterlab/example-console", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/console": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/rendermime": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@lumino/commands": "^1.12.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/console": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/rendermime": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@lumino/commands": "^1.20.0", + "@lumino/widgets": "^1.33.0", "es6-promise": "~4.2.8" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.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": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/console/templates/index.html b/examples/console/templates/index.html index ed2bdc7..a839607 100644 --- a/examples/console/templates/index.html +++ b/examples/console/templates/index.html @@ -1,3 +1,8 @@ + + @@ -7,10 +12,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/webpack.config.js b/examples/console/webpack.config.js index 9f54b0f..4c025db 100644 --- a/examples/console/webpack.config.js +++ b/examples/console/webpack.config.js @@ -1,4 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], @@ -12,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()) } }, { @@ -29,20 +35,16 @@ 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: () => '/' } }) diff --git a/examples/example.spec.ts b/examples/example.spec.ts new file mode 100644 index 0000000..cebde48 --- /dev/null +++ b/examples/example.spec.ts @@ -0,0 +1,49 @@ +/* + * 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.waitForNavigation(); + + await expect(page.locator('#jupyter-config-data')).toHaveCount(1); + + await waitForTestEnd; + + expect(errorLogs).toEqual(0); // Missing lsp handlers +}); diff --git a/examples/example_check.py b/examples/example_check.py index 539b05f..8009f62 100644 --- a/examples/example_check.py +++ b/examples/example_check.py @@ -1,38 +1,34 @@ - # -*- 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 -from os import path as osp import os import shutil import sys -import subprocess +from pathlib import Path -from tornado.ioloop import IOLoop -from traitlets import Bool, Dict, Unicode -from jupyter_server.serverapp import ServerApp +from jupyterlab.browser_check import run_async_process, run_test from jupyterlab.labapp import get_app_dir -from jupyterlab.browser_check import run_test, run_async_process -from jupyter_server.serverapp import ServerApp - -here = osp.abspath(osp.dirname(__file__)) +here = Path(__file__).parent.resolve() +TEST_FILE = here / "example.spec.ts" 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')) - spec = importlib.util.spec_from_file_location('example', mod_path) + example_dir = Path(sys.argv.pop()) + 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) sys.modules[__name__] = mod @@ -41,45 +37,47 @@ class App(mod.ExampleApp): """An app that launches an example and waits for it to start up, checking for JS console errors, JS errors, and Python logged errors. """ + name = __name__ open_browser = False - serverapp_config = { - "base_url": "/foo/", - "root_dir": osp.abspath(example_dir) - } - ip = '127.0.0.1' + serverapp_config = {"base_url": "/foo/", "root_dir": str(example_dir.resolve())} + ip = "127.0.0.1" def initialize_settings(self): run_test(self.serverapp, run_browser) super().initialize_settings() def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': App - } - ] + return [{"module": __name__, "app": App}] 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.""" # 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@^4"], cwd=target) - shutil.copy(osp.join(here, 'chrome-example-test.js'), osp.join(target, 'chrome-example-test.js')) - await run_async_process(["node", "chrome-example-test.js", url], cwd=target) - -if __name__ == '__main__': + 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 + + shutil.copy( + str(TEST_FILE), + str(test_target), + ) + + current_env = os.environ.copy() + current_env["BASE_URL"] = url + await run_async_process(["npx", "playwright", "test"], env=current_env, cwd=str(target)) + + +if __name__ == "__main__": main() diff --git a/examples/federated/core_package/bootstrap.js b/examples/federated/core_package/bootstrap.js index 1f8cb3a..7b20297 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 15f5737..7274917 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 00c4214..fa3eb83 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.4.2", + "version": "3.0.0-alpha.12", "private": true, "scripts": { "build": "npm run clean && webpack", @@ -8,169 +8,156 @@ "watch": "npm run clean && webpack --watch" }, "resolutions": { - "@jupyterlab/application": "~3.3.0-alpha.15", - "@jupyterlab/application-extension": "~3.3.0-alpha.15", - "@jupyterlab/apputils": "~3.3.0-alpha.15", - "@jupyterlab/apputils-extension": "~3.3.0-alpha.15", - "@jupyterlab/attachments": "~3.3.0-alpha.15", - "@jupyterlab/cells": "~3.3.0-alpha.15", - "@jupyterlab/celltags": "~3.3.0-alpha.15", - "@jupyterlab/celltags-extension": "~3.3.0-alpha.15", - "@jupyterlab/codeeditor": "~3.3.0-alpha.15", - "@jupyterlab/codemirror": "~3.3.0-alpha.15", - "@jupyterlab/codemirror-extension": "~3.3.0-alpha.15", - "@jupyterlab/completer": "~3.3.0-alpha.15", - "@jupyterlab/completer-extension": "~3.3.0-alpha.15", - "@jupyterlab/console": "~3.3.0-alpha.15", - "@jupyterlab/console-extension": "~3.3.0-alpha.15", - "@jupyterlab/coreutils": "~5.3.0-alpha.15", - "@jupyterlab/csvviewer": "~3.3.0-alpha.15", - "@jupyterlab/csvviewer-extension": "~3.3.0-alpha.15", - "@jupyterlab/debugger": "~3.3.0-alpha.15", - "@jupyterlab/debugger-extension": "~3.3.0-alpha.15", - "@jupyterlab/docmanager": "~3.3.0-alpha.15", - "@jupyterlab/docmanager-extension": "~3.3.0-alpha.15", - "@jupyterlab/docregistry": "~3.3.0-alpha.15", - "@jupyterlab/documentsearch": "~3.3.0-alpha.15", - "@jupyterlab/documentsearch-extension": "~3.3.0-alpha.15", - "@jupyterlab/extensionmanager": "~3.3.0-alpha.15", - "@jupyterlab/extensionmanager-extension": "~3.3.0-alpha.15", - "@jupyterlab/filebrowser": "~3.3.0-alpha.15", - "@jupyterlab/filebrowser-extension": "~3.3.0-alpha.15", - "@jupyterlab/fileeditor": "~3.3.0-alpha.15", - "@jupyterlab/fileeditor-extension": "~3.3.0-alpha.15", - "@jupyterlab/help-extension": "~3.3.0-alpha.15", - "@jupyterlab/htmlviewer": "~3.3.0-alpha.15", - "@jupyterlab/htmlviewer-extension": "~3.3.0-alpha.15", - "@jupyterlab/hub-extension": "~3.3.0-alpha.15", - "@jupyterlab/imageviewer": "~3.3.0-alpha.15", - "@jupyterlab/imageviewer-extension": "~3.3.0-alpha.15", - "@jupyterlab/inspector": "~3.3.0-alpha.15", - "@jupyterlab/inspector-extension": "~3.3.0-alpha.15", - "@jupyterlab/javascript-extension": "~3.3.0-alpha.15", - "@jupyterlab/json-extension": "~3.3.0-alpha.15", - "@jupyterlab/launcher": "~3.3.0-alpha.15", - "@jupyterlab/launcher-extension": "~3.3.0-alpha.15", - "@jupyterlab/logconsole": "~3.3.0-alpha.15", - "@jupyterlab/logconsole-extension": "~3.3.0-alpha.15", - "@jupyterlab/mainmenu": "~3.3.0-alpha.15", - "@jupyterlab/mainmenu-extension": "~3.3.0-alpha.15", - "@jupyterlab/mathjax2": "~3.3.0-alpha.15", - "@jupyterlab/mathjax2-extension": "~3.3.0-alpha.15", - "@jupyterlab/metapackage": "~3.3.0-alpha.15", - "@jupyterlab/nbconvert-css": "~3.3.0-alpha.15", - "@jupyterlab/nbformat": "~3.3.0-alpha.15", - "@jupyterlab/notebook": "~3.3.0-alpha.15", - "@jupyterlab/notebook-extension": "~3.3.0-alpha.15", - "@jupyterlab/observables": "~4.3.0-alpha.15", - "@jupyterlab/outputarea": "~3.3.0-alpha.15", - "@jupyterlab/pdf-extension": "~3.3.0-alpha.15", - "@jupyterlab/property-inspector": "~3.3.0-alpha.15", - "@jupyterlab/rendermime": "~3.3.0-alpha.15", - "@jupyterlab/rendermime-extension": "~3.3.0-alpha.15", - "@jupyterlab/rendermime-interfaces": "~3.3.0-alpha.15", - "@jupyterlab/running": "~3.3.0-alpha.15", - "@jupyterlab/running-extension": "~3.3.0-alpha.15", - "@jupyterlab/services": "~6.0.0-alpha.15", - "@jupyterlab/settingeditor": "~3.3.0-alpha.15", - "@jupyterlab/settingeditor-extension": "~3.3.0-alpha.15", - "@jupyterlab/settingregistry": "~3.3.0-alpha.15", - "@jupyterlab/shortcuts-extension": "~3.3.0-alpha.15", - "@jupyterlab/statedb": "~3.3.0-alpha.15", - "@jupyterlab/statusbar": "~3.3.0-alpha.15", - "@jupyterlab/statusbar-extension": "~3.3.0-alpha.15", - "@jupyterlab/terminal": "~3.3.0-alpha.15", - "@jupyterlab/terminal-extension": "~3.3.0-alpha.15", - "@jupyterlab/theme-dark-extension": "~3.3.0-alpha.15", - "@jupyterlab/theme-light-extension": "~3.3.0-alpha.15", - "@jupyterlab/toc": "~5.3.0-alpha.15", - "@jupyterlab/toc-extension": "~5.3.0-alpha.15", - "@jupyterlab/tooltip": "~3.3.0-alpha.15", - "@jupyterlab/tooltip-extension": "~3.3.0-alpha.15", - "@jupyterlab/translation": "~3.3.0-alpha.15", - "@jupyterlab/translation-extension": "~3.3.0-alpha.15", - "@jupyterlab/ui-components": "~3.3.0-alpha.14", - "@jupyterlab/ui-components-extension": "~3.3.0-alpha.15", - "@jupyterlab/vdom": "~3.3.0-alpha.15", - "@jupyterlab/vdom-extension": "~3.3.0-alpha.15", - "@jupyterlab/vega5-extension": "~3.3.0-alpha.15", - "@lumino/algorithm": "^1.3.3", - "@lumino/application": "^1.13.1", - "@lumino/commands": "^1.12.0", - "@lumino/coreutils": "^1.5.3", - "@lumino/disposable": "^1.4.3", - "@lumino/domutils": "^1.2.3", - "@lumino/dragdrop": "^1.7.1", - "@lumino/messaging": "^1.4.3", - "@lumino/properties": "^1.2.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.18.0", + "@jupyterlab/application": "~4.0.0-alpha.12", + "@jupyterlab/application-extension": "~4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.2", + "@jupyterlab/apputils-extension": "~4.0.0-alpha.12", + "@jupyterlab/attachments": "^4.0.0-alpha.2", + "@jupyterlab/cells": "~4.0.0-alpha.3", + "@jupyterlab/celltags": "~4.0.0-alpha.3", + "@jupyterlab/celltags-extension": "~4.0.0-alpha.12", + "@jupyterlab/codeeditor": "^4.0.0-alpha.2", + "@jupyterlab/codemirror-extension": "~4.0.0-alpha.12", + "@jupyterlab/collaboration": "^4.0.0-alpha.11", + "@jupyterlab/collaboration-extension": "~4.0.0-alpha.11", + "@jupyterlab/completer": "^4.0.0-alpha.2", + "@jupyterlab/completer-extension": "~4.0.0-alpha.12", + "@jupyterlab/console": "^4.0.0-alpha.2", + "@jupyterlab/console-extension": "~4.0.0-alpha.12", + "@jupyterlab/coreutils": "~6.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/debugger": "^4.0.0-alpha.2", + "@jupyterlab/debugger-extension": "~4.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.2", + "@jupyterlab/docmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch": "^4.0.0-alpha.2", + "@jupyterlab/documentsearch-extension": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager": "^4.0.0-alpha.2", + "@jupyterlab/extensionmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser": "^4.0.0-alpha.2", + "@jupyterlab/filebrowser-extension": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor": "^4.0.0-alpha.2", + "@jupyterlab/fileeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/help-extension": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/hub-extension": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer": "^4.0.0-alpha.2", + "@jupyterlab/imageviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/inspector": "^4.0.0-alpha.2", + "@jupyterlab/inspector-extension": "~4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "~4.0.0-alpha.12", + "@jupyterlab/json-extension": "~4.0.0-alpha.12", + "@jupyterlab/launcher": "^4.0.0-alpha.2", + "@jupyterlab/launcher-extension": "~4.0.0-alpha.12", + "@jupyterlab/logconsole": "^4.0.0-alpha.2", + "@jupyterlab/logconsole-extension": "~4.0.0-alpha.12", + "@jupyterlab/lsp": "^4.0.0-alpha.2", + "@jupyterlab/lsp-extension": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu": "^4.0.0-alpha.2", + "@jupyterlab/mainmenu-extension": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "~4.0.0-alpha.12", + "@jupyterlab/notebook": "^4.0.0-alpha.2", + "@jupyterlab/notebook-extension": "~4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime": "^4.0.0-alpha.2", + "@jupyterlab/rendermime-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-interfaces": "^3.8.0-alpha.9", + "@jupyterlab/services": "^7.0.0-alpha.2", + "@jupyterlab/settingeditor": "^4.0.0-alpha.2", + "@jupyterlab/settingeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.2", + "@jupyterlab/shortcuts-extension": "~4.0.0-alpha.12", + "@jupyterlab/statedb": "^4.0.0-alpha.2", + "@jupyterlab/statusbar": "^4.0.0-alpha.2", + "@jupyterlab/statusbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/terminal": "^4.0.0-alpha.2", + "@jupyterlab/terminal-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "~4.0.0-alpha.12", + "@jupyterlab/toc-extension": "~6.0.0-alpha.12", + "@jupyterlab/tooltip": "^4.0.0-alpha.2", + "@jupyterlab/tooltip-extension": "~4.0.0-alpha.12", + "@jupyterlab/translation": "~4.0.0-alpha.12", + "@jupyterlab/translation-extension": "~4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.17", + "@jupyterlab/ui-components-extension": "~4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "~4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "~4.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/application": "^1.29.0", + "@lumino/commands": "^1.19.0", + "@lumino/coreutils": "^1.11.1", + "@lumino/disposable": "^1.10.1", + "@lumino/domutils": "^1.8.1", + "@lumino/dragdrop": "^1.13.1", + "@lumino/messaging": "^1.10.1", + "@lumino/properties": "^1.8.1", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "react": "^17.0.1", - "react-dom": "^17.0.1" + "react-dom": "^17.0.1", + "yjs": "^13.5.34" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/application-extension": "^3.3.2", - "@jupyterlab/apputils-extension": "^3.3.2", - "@jupyterlab/celltags-extension": "^3.3.2", - "@jupyterlab/codemirror-extension": "^3.3.2", - "@jupyterlab/completer-extension": "^3.3.2", - "@jupyterlab/console-extension": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/csvviewer-extension": "^3.3.2", - "@jupyterlab/docmanager-extension": "^3.3.2", - "@jupyterlab/documentsearch-extension": "^3.3.2", - "@jupyterlab/extensionmanager-extension": "^3.3.2", - "@jupyterlab/filebrowser-extension": "^3.3.2", - "@jupyterlab/fileeditor-extension": "^3.3.2", - "@jupyterlab/help-extension": "^3.3.2", - "@jupyterlab/htmlviewer-extension": "^3.3.2", - "@jupyterlab/hub-extension": "^3.3.2", - "@jupyterlab/imageviewer-extension": "^3.3.2", - "@jupyterlab/inspector-extension": "^3.3.2", - "@jupyterlab/javascript-extension": "^3.3.2", - "@jupyterlab/json-extension": "^3.3.2", - "@jupyterlab/launcher-extension": "^3.3.2", - "@jupyterlab/logconsole-extension": "^3.3.2", - "@jupyterlab/mainmenu-extension": "^3.3.2", - "@jupyterlab/mathjax2-extension": "^3.3.2", - "@jupyterlab/notebook-extension": "^3.3.2", - "@jupyterlab/pdf-extension": "^3.3.2", - "@jupyterlab/rendermime-extension": "^3.3.2", - "@jupyterlab/settingeditor-extension": "^3.3.2", - "@jupyterlab/shortcuts-extension": "^3.3.2", - "@jupyterlab/statusbar-extension": "^3.3.2", - "@jupyterlab/terminal-extension": "^3.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@jupyterlab/toc-extension": "^5.3.2", - "@jupyterlab/tooltip-extension": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/translation-extension": "^3.3.2", - "@jupyterlab/ui-components-extension": "^3.3.2", - "@jupyterlab/vdom-extension": "^3.3.2", - "@jupyterlab/vega5-extension": "^3.3.2" + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/application-extension": "^4.0.0-alpha.12", + "@jupyterlab/apputils-extension": "^4.0.0-alpha.12", + "@jupyterlab/celltags-extension": "^4.0.0-alpha.12", + "@jupyterlab/codemirror-extension": "^4.0.0-alpha.12", + "@jupyterlab/completer-extension": "^4.0.0-alpha.12", + "@jupyterlab/console-extension": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "^4.0.0-alpha.12", + "@jupyterlab/debugger-extension": "^4.0.0-alpha.12", + "@jupyterlab/docmanager-extension": "^4.0.0-alpha.12", + "@jupyterlab/documentsearch-extension": "^4.0.0-alpha.12", + "@jupyterlab/extensionmanager-extension": "^4.0.0-alpha.12", + "@jupyterlab/filebrowser-extension": "^4.0.0-alpha.12", + "@jupyterlab/fileeditor-extension": "^4.0.0-alpha.12", + "@jupyterlab/help-extension": "^4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "^4.0.0-alpha.12", + "@jupyterlab/hub-extension": "^4.0.0-alpha.12", + "@jupyterlab/imageviewer-extension": "^4.0.0-alpha.12", + "@jupyterlab/inspector-extension": "^4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "^4.0.0-alpha.12", + "@jupyterlab/json-extension": "^4.0.0-alpha.12", + "@jupyterlab/launcher-extension": "^4.0.0-alpha.12", + "@jupyterlab/logconsole-extension": "^4.0.0-alpha.12", + "@jupyterlab/lsp-extension": "^4.0.0-alpha.12", + "@jupyterlab/mainmenu-extension": "^4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "^4.0.0-alpha.12", + "@jupyterlab/notebook-extension": "^4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "^4.0.0-alpha.12", + "@jupyterlab/rendermime-extension": "^4.0.0-alpha.12", + "@jupyterlab/settingeditor-extension": "^4.0.0-alpha.12", + "@jupyterlab/shortcuts-extension": "^4.0.0-alpha.12", + "@jupyterlab/statusbar-extension": "^4.0.0-alpha.12", + "@jupyterlab/terminal-extension": "^4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@jupyterlab/toc-extension": "^6.0.0-alpha.12", + "@jupyterlab/tooltip-extension": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/translation-extension": "^4.0.0-alpha.12", + "@jupyterlab/ui-components-extension": "^4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "^4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "^4.0.0-alpha.12" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", "copy-webpack-plugin": "^6.0.1", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "fs-extra": "^9.0.1", "glob": "~7.1.6", "handlebars": "^4.5.3", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.0", + "mini-svg-data-uri": "^1.4.4", "read-package-tree": "^5.3.1", "rimraf": "~3.0.0", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", + "style-loader": "~3.3.1", "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", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0" }, "jupyterlab": { @@ -181,7 +168,9 @@ "singletonPackages": [ "@jupyterlab/application", "@jupyterlab/apputils", + "@jupyterlab/attachments", "@jupyterlab/codeeditor", + "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", @@ -195,6 +184,7 @@ "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/notebook", "@jupyterlab/rendermime", @@ -206,6 +196,7 @@ "@jupyterlab/statusbar", "@jupyterlab/terminal", "@jupyterlab/tooltip", + "@jupyterlab/translation", "@jupyterlab/ui-components", "@lumino/algorithm", "@lumino/application", @@ -220,7 +211,8 @@ "@lumino/virtualdom", "@lumino/widgets", "react", - "react-dom" + "react-dom", + "yjs" ], "extensions": [ "@jupyterlab/application-extension", @@ -230,6 +222,7 @@ "@jupyterlab/completer-extension", "@jupyterlab/console-extension", "@jupyterlab/csvviewer-extension", + "@jupyterlab/debugger-extension", "@jupyterlab/docmanager-extension", "@jupyterlab/documentsearch-extension", "@jupyterlab/extensionmanager-extension", @@ -240,25 +233,26 @@ "@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/notebook-extension", + "@jupyterlab/pdf-extension", "@jupyterlab/rendermime-extension", "@jupyterlab/settingeditor-extension", "@jupyterlab/shortcuts-extension", "@jupyterlab/statusbar-extension", "@jupyterlab/terminal-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 d424716..6471ecf 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/main.py b/examples/federated/main.py index 5497e6b..aa69a74 100644 --- a/examples/federated/main.py +++ b/examples/federated/main.py @@ -1,8 +1,8 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -import os import json +import os from jupyterlab_server import LabServerApp @@ -10,35 +10,33 @@ # Turn off the Jupyter configuration system so configuration files on disk do # not affect this app. This helps this app to truly be standalone. -os.environ["JUPYTER_NO_CONFIG"]="1" +os.environ["JUPYTER_NO_CONFIG"] = "1" + +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] + class ExampleApp(LabServerApp): - name = 'lab' + name = "lab" load_other_extensions = False - app_name = 'JupyterLab Example App with Prebuilt Extensions' - app_settings_dir = os.path.join(HERE, 'data', 'application_settings') + app_name = "JupyterLab Example App with Prebuilt Extensions" + app_settings_dir = os.path.join(HERE, "data", "application_settings") app_version = version - schemas_dir = os.path.join(HERE, 'data', 'schemas') - static_dir = os.path.join(HERE, 'core_package', 'static') - templates_dir = os.path.join(HERE, 'templates') - themes_dir = os.path.join(HERE, 'data', 'themes') - user_settings_dir = os.path.join(HERE, 'data', 'user_settings') - workspaces_dir = os.path.join(HERE, 'data', 'workspaces') + schemas_dir = os.path.join(HERE, "data", "schemas") + static_dir = os.path.join(HERE, "core_package", "static") + templates_dir = os.path.join(HERE, "templates") + themes_dir = os.path.join(HERE, "data", "themes") + user_settings_dir = os.path.join(HERE, "data", "user_settings") + workspaces_dir = os.path.join(HERE, "data", "workspaces") # Set the location for prebuilt extensions, overriding the default # of looking in each of the Jupyter data paths. labextensions_path = [os.path.join(HERE, "labextensions")] -if __name__ == '__main__': + +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/federated/md_package/index.js b/examples/federated/md_package/index.js index 763ac29..65fd948 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 7f12979..c858276 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 007adf1..dc9477f 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.4.2", + "version": "3.0.0-alpha.12", "private": true, "main": "./index.js", "scripts": { @@ -8,13 +8,13 @@ "clean": "rimraf ../labextensions/@jupyterlab/example-federated-md" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/example-federated-middle": "^2.4.2", - "@jupyterlab/markdownviewer-extension": "^3.3.2", - "@lumino/widgets": "^1.19.0" + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/example-federated-middle": "^3.0.0-alpha.12", + "@jupyterlab/markdownviewer-extension": "^4.0.0-alpha.12", + "@lumino/widgets": "^1.33.0" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", "rimraf": "~3.0.0" }, "jupyterlab": { diff --git a/examples/federated/md_package/style/index.css b/examples/federated/md_package/style/index.css index 6a25f88..ab24a9a 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 bc0a73c..e6181dc 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.4.2", + "version": "3.0.0-alpha.12", "private": true, "scripts": { "build": "npm run clean && build-labextension --core-path ../core_package .", "clean": "rimraf ../labextensions/@jupyterlab/example-federated-middle" }, "dependencies": { - "@lumino/coreutils": "^1.5.3" + "@lumino/coreutils": "^1.12.0" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", "rimraf": "~3.0.0" }, "publishConfig": { diff --git a/examples/federated/package.json b/examples/federated/package.json index e904fc2..30d124e 100644 --- a/examples/federated/package.json +++ b/examples/federated/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/example-federated", - "version": "2.4.2", + "version": "3.0.0-alpha.12", "private": true, "scripts": { "build": "npm run build:core && npm run build:middle && npm run build:md && npm run build:phosphor", diff --git a/examples/federated/phosphor_package/index.js b/examples/federated/phosphor_package/index.js index a884195..f57e38a 100644 --- a/examples/federated/phosphor_package/index.js +++ b/examples/federated/phosphor_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. diff --git a/examples/federated/phosphor_package/package.json b/examples/federated/phosphor_package/package.json index 7d8d898..d4e24b9 100644 --- a/examples/federated/phosphor_package/package.json +++ b/examples/federated/phosphor_package/package.json @@ -1,17 +1,17 @@ { "name": "@jupyterlab/example-federated-phosphor", - "version": "2.4.2", + "version": "3.0.0-alpha.12", "private": true, "scripts": { "build": "npm run clean && build-labextension --core-path ../core_package .", "clean": "rimraf ../labextensions/@jupyterlab/example-federated-phosphor" }, "dependencies": { - "@jupyterlab/apputils": "^3.3.2", + "@jupyterlab/apputils": "^4.0.0-alpha.12", "@phosphor/coreutils": "^1.0.0" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", "rimraf": "~3.0.0" }, "publishConfig": { diff --git a/examples/federated/templates/index.html b/examples/federated/templates/index.html index a782a36..fde08a8 100644 --- a/examples/federated/templates/index.html +++ b/examples/federated/templates/index.html @@ -1,3 +1,8 @@ + + @@ -6,10 +11,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/main.py b/examples/filebrowser/main.py index d9864ad..7344604 100644 --- a/examples/filebrowser/main.py +++ b/examples/filebrowser/main.py @@ -11,32 +11,28 @@ run ``python main.py``. """ -import os import json +import os -from jupyterlab_server import LabServerApp from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin, ExtensionHandlerJinjaMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerJinjaMixin, + ExtensionHandlerMixin, +) from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp HERE = os.path.dirname(__file__) -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] + def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] -class ExampleHandler( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, - JupyterHandler - ): + +class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): """Handle requests between the main app page and notebook server.""" def get(self): @@ -44,46 +40,44 @@ def get(self): config_data = { # Use camelCase here, since that's what the lab components expect "appVersion": version, - 'baseUrl': self.base_url, - 'token': self.settings['token'], - 'fullStaticUrl': ujoin(self.base_url, 'static', self.name), - 'frontendUrl': ujoin(self.base_url, 'example/'), + "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', + "index.html", static=self.static_url, base_url=self.base_url, - token=self.settings['token'], - page_config=config_data - ) + token=self.settings["token"], + page_config=config_data, ) + ) class ExampleApp(LabServerApp): - extension_url = '/example' - default_url = '/example' + extension_url = "/example" + default_url = "/example" app_url = "/example" load_other_extensions = False name = __name__ - app_name = 'JupyterLab Example File Browser' - static_dir = os.path.join(HERE, 'build') - templates_dir = os.path.join(HERE, 'templates') + app_name = "JupyterLab Example File Browser" + static_dir = os.path.join(HERE, "build") + templates_dir = os.path.join(HERE, "templates") app_version = version - 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') - + 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. - """ + """Add example handler to Lab Server's handler list.""" super().initialize_handlers() - self.handlers.append(('/example', ExampleHandler)) + self.handlers.append(("/example", ExampleHandler)) -if __name__ == '__main__': +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/filebrowser/package.json b/examples/filebrowser/package.json index 96399ad..0f5dd1a 100644 --- a/examples/filebrowser/package.json +++ b/examples/filebrowser/package.json @@ -1,43 +1,38 @@ { "name": "@jupyterlab/example-filebrowser", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docmanager": "^3.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/filebrowser": "^3.3.2", - "@jupyterlab/fileeditor": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/commands": "^1.12.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/filebrowser": "^4.0.0-alpha.12", + "@jupyterlab/fileeditor": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/algorithm": "^1.9.1", + "@lumino/commands": "^1.20.0", + "@lumino/widgets": "^1.33.0", "es6-promise": "~4.2.8" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.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": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/filebrowser/src/index.ts b/examples/filebrowser/src/index.ts index d27a1a1..bf86169 100644 --- a/examples/filebrowser/src/index.ts +++ b/examples/filebrowser/src/index.ts @@ -21,7 +21,7 @@ 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, @@ -42,7 +42,7 @@ import { TranslationManager } from '@jupyterlab/translation'; -import { addIcon } from '@jupyterlab/ui-components'; +import { addIcon, ToolbarButton } from '@jupyterlab/ui-components'; const LANG = 'en'; diff --git a/examples/filebrowser/templates/index.html b/examples/filebrowser/templates/index.html index ed2bdc7..a839607 100644 --- a/examples/filebrowser/templates/index.html +++ b/examples/filebrowser/templates/index.html @@ -1,3 +1,8 @@ + + @@ -7,10 +12,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 bcb8469..95f3a7e 100644 --- a/examples/filebrowser/webpack.config.js +++ b/examples/filebrowser/webpack.config.js @@ -1,4 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], @@ -12,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()) } }, { @@ -29,20 +35,16 @@ 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: () => '/' } }) diff --git a/examples/notebook/main.py b/examples/notebook/main.py index 18decff..4937d6b 100644 --- a/examples/notebook/main.py +++ b/examples/notebook/main.py @@ -11,32 +11,28 @@ run ``python main.py``. """ -import os import json +import os -from jupyterlab_server import LabServerApp from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin, ExtensionHandlerJinjaMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerJinjaMixin, + ExtensionHandlerMixin, +) from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp HERE = os.path.dirname(__file__) -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] + def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] -class ExampleHandler( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, - JupyterHandler - ): + +class ExampleHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): """ Serve a notebook file from the filesystem in the notebook interface """ @@ -44,59 +40,51 @@ class ExampleHandler( 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') + 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, - 'token': self.settings['token'], - 'notebookPath': 'test.ipynb', - 'fullStaticUrl': ujoin(self.base_url, 'static', self.name), - 'frontendUrl': ujoin(self.base_url, 'example/'), - 'mathjaxUrl': mathjax_url, - 'mathjaxConfig': mathjax_config + "baseUrl": self.base_url, + "token": self.settings["token"], + "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( - 'index.html', + "index.html", static=self.static_url, base_url=self.base_url, - token=self.settings['token'], - page_config=config_data - ) + token=self.settings["token"], + page_config=config_data, ) + ) class ExampleApp(LabServerApp): - extension_url = '/example' - default_url = '/example' + extension_url = "/example" + default_url = "/example" app_url = "/example" name = __name__ - app_name = 'JupyterLab Example Notebook' - app_settings_dir = os.path.join(HERE, 'build', 'application_settings') - schemas_dir = os.path.join(HERE, 'build', 'schemas') - static_dir = os.path.join(HERE, 'build') - templates_dir = os.path.join(HERE, 'templates') - 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') - - serverapp_config = { - "jpserver_extensions": { - "nbclassic": True - } - } + app_name = "JupyterLab Example Notebook" + app_settings_dir = os.path.join(HERE, "build", "application_settings") + schemas_dir = os.path.join(HERE, "build", "schemas") + static_dir = os.path.join(HERE, "build") + templates_dir = os.path.join(HERE, "templates") + 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) - ) + """Add example handler to Lab Server's handler list.""" + self.handlers.append(("/example", ExampleHandler)) -if __name__ == '__main__': +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/notebook/package.json b/examples/notebook/package.json index a8fcad1..f95df72 100644 --- a/examples/notebook/package.json +++ b/examples/notebook/package.json @@ -1,43 +1,39 @@ { "name": "@jupyterlab/example-notebook", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/completer": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docmanager": "^3.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/documentsearch": "^3.3.2", - "@jupyterlab/mathjax2": "^3.3.2", - "@jupyterlab/notebook": "^3.3.2", - "@jupyterlab/rendermime": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@lumino/commands": "^1.12.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/completer": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/documentsearch": "^4.0.0-alpha.12", + "@jupyterlab/mathjax2": "^4.0.0-alpha.12", + "@jupyterlab/notebook": "^4.0.0-alpha.12", + "@jupyterlab/rendermime": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@lumino/commands": "^1.20.0", + "@lumino/widgets": "^1.33.0", "es6-promise": "~4.2.8" }, "devDependencies": { - "@types/codemirror": "^0.0.109", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.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": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/notebook/src/commands.ts b/examples/notebook/src/commands.ts index dfca603..5f980aa 100644 --- a/examples/notebook/src/commands.ts +++ b/examples/notebook/src/commands.ts @@ -1,15 +1,25 @@ +/* + * 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 { 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 { CommandRegistry } from '@lumino/commands'; +import { CommandPalette, Widget } from '@lumino/widgets'; /** * The map of command ids used by the notebook. @@ -48,7 +58,7 @@ export const SetupCommands = ( palette: CommandPalette, nbWidget: NotebookPanel, handler: CompletionHandler -) => { +): void => { // Add commands. commands.addCommand(cmdIds.invoke, { label: 'Completer: Invoke', @@ -79,24 +89,53 @@ export const SetupCommands = ( execute: () => nbWidget.context.save() }); - let searchInstance: SearchInstance | undefined; + let searchInstance: SearchDocumentView | undefined; commands.addCommand(cmdIds.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(); + }); + + /** + * Dispose resources when the widget is disposed. + */ + nbWidget.disposed.connect(() => { + searchInstance?.dispose(); + searchModel.dispose(); + provider.dispose(); + }); + } + + 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(); + } } - 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(); + searchInstance.focusSearchInput(); } }); commands.addCommand(cmdIds.findNext, { @@ -106,8 +145,7 @@ export const SetupCommands = ( if (!searchInstance) { return; } - await searchInstance.provider.highlightNext(); - searchInstance.updateIndices(); + await searchInstance.model.highlightNext(); } }); commands.addCommand(cmdIds.findPrevious, { @@ -117,8 +155,7 @@ export const SetupCommands = ( if (!searchInstance) { return; } - await searchInstance.provider.highlightPrevious(); - searchInstance.updateIndices(); + await searchInstance.model.highlightPrevious(); } }); commands.addCommand(cmdIds.interrupt, { diff --git a/examples/notebook/src/index.ts b/examples/notebook/src/index.ts old mode 100755 new mode 100644 index f656090..e0f1611 --- a/examples/notebook/src/index.ts +++ b/examples/notebook/src/index.ts @@ -32,7 +32,8 @@ import { Completer, CompleterModel, CompletionHandler, - KernelConnector + ConnectorProxy, + KernelCompleterProvider } from '@jupyterlab/completer'; import { editorServices } from '@jupyterlab/codemirror'; @@ -45,6 +46,7 @@ import { standardRendererFactories as initialFactories, RenderMimeRegistry } from '@jupyterlab/rendermime'; + import { SetupCommands } from './commands'; function main(): void { @@ -116,15 +118,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 connector = new ConnectorProxy( + { widget: nbWidget, editor, session: sessionContext.session }, + [provider], + timeout + ); const handler = new CompletionHandler({ completer, connector }); void sessionContext.ready.then(() => { - handler.connector = new KernelConnector({ - session: sessionContext.session - }); + const provider = new KernelCompleterProvider(); + const connector = new ConnectorProxy( + { widget: nbWidget, editor, session: sessionContext.session }, + [provider], + timeout + ); + + handler.connector = connector; }); // Set the handler's editor. diff --git a/examples/notebook/templates/index.html b/examples/notebook/templates/index.html index ed2bdc7..a839607 100644 --- a/examples/notebook/templates/index.html +++ b/examples/notebook/templates/index.html @@ -1,3 +1,8 @@ + + @@ -7,10 +12,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/webpack.config.js b/examples/notebook/webpack.config.js index 8996d2e..eb29dd6 100644 --- a/examples/notebook/webpack.config.js +++ b/examples/notebook/webpack.config.js @@ -1,4 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], @@ -12,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()) } }, { @@ -29,20 +35,16 @@ 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: () => '/' } }) diff --git a/examples/terminal/main.py b/examples/terminal/main.py index 146b981..9e36fa5 100644 --- a/examples/terminal/main.py +++ b/examples/terminal/main.py @@ -11,78 +11,74 @@ run ``python main.py``. """ -import os import json +import os -from jupyterlab_server import LabServerApp from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerMixin, ExtensionHandlerJinjaMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerJinjaMixin, + ExtensionHandlerMixin, +) from jupyter_server.utils import url_path_join as ujoin +from jupyterlab_server import LabServerApp HERE = os.path.dirname(__file__) -with open(os.path.join(HERE, 'package.json')) as fid: - version = json.load(fid)['version'] +with open(os.path.join(HERE, "package.json")) as fid: + version = json.load(fid)["version"] + def _jupyter_server_extension_points(): - return [ - { - 'module': __name__, - 'app': ExampleApp - } - ] + return [{"module": __name__, "app": ExampleApp}] -class ExampleHandler( - ExtensionHandlerJinjaMixin, - ExtensionHandlerMixin, - JupyterHandler - ): + +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.""" - available = self.settings['terminals_available'] + available = self.settings["terminals_available"] config_data = { # Use camelCase here, since that's what the lab components expect "appVersion": version, - 'baseUrl': self.base_url, - 'token': self.settings['token'], - 'fullStaticUrl': ujoin(self.base_url, 'static', self.name), - 'frontendUrl': ujoin(self.base_url, 'example/'), - 'terminalsAvailable': available + "baseUrl": self.base_url, + "token": self.settings["token"], + "fullStaticUrl": ujoin(self.base_url, "static", self.name), + "frontendUrl": ujoin(self.base_url, "example/"), + "terminalsAvailable": available, } return self.write( - self.render_template('index.html', - static=self.static_url, - base_url=self.base_url, - token=self.settings['token'], - terminals_available=available, - page_config=config_data) + self.render_template( + "index.html", + static=self.static_url, + base_url=self.base_url, + token=self.settings["token"], + terminals_available=available, + page_config=config_data, ) + ) class ExampleApp(LabServerApp): - extension_url = '/example' - default_url = '/example' + extension_url = "/example" + default_url = "/example" app_url = "/example" name = __name__ load_other_extensions = False - app_name = 'JupyterLab Example Terminal' - app_settings_dir = os.path.join(HERE, 'build', 'application_settings') - schemas_dir = os.path.join(HERE, 'build', 'schemas') - static_dir = os.path.join(HERE, 'build') - templates_dir = os.path.join(HERE, 'templates') - 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') + app_name = "JupyterLab Example Terminal" + app_settings_dir = os.path.join(HERE, "build", "application_settings") + schemas_dir = os.path.join(HERE, "build", "schemas") + static_dir = os.path.join(HERE, "build") + templates_dir = os.path.join(HERE, "templates") + 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) - ) + """Add example handler to Lab Server's handler list.""" + self.handlers.append(("/example", ExampleHandler)) + -if __name__ == '__main__': +if __name__ == "__main__": ExampleApp.launch_instance() diff --git a/examples/terminal/package.json b/examples/terminal/package.json index 047ec8a..a795149 100644 --- a/examples/terminal/package.json +++ b/examples/terminal/package.json @@ -1,33 +1,29 @@ { "name": "@jupyterlab/example-terminal", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "scripts": { "build": "tsc -p src && webpack", "clean": "rimraf build" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/terminal": "^3.3.2", - "@jupyterlab/theme-light-extension": "^3.3.2", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/terminal": "^4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "^4.0.0-alpha.12", + "@lumino/widgets": "^1.33.0", "es6-promise": "~4.2.8" }, "devDependencies": { - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", + "css-loader": "^6.7.1", "mini-css-extract-plugin": "~1.3.2", - "raw-loader": "~4.0.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": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2", "whatwg-fetch": "^3.0.0" } } diff --git a/examples/terminal/templates/index.html b/examples/terminal/templates/index.html index c8e2300..66b0cf6 100644 --- a/examples/terminal/templates/index.html +++ b/examples/terminal/templates/index.html @@ -1,3 +1,8 @@ + + @@ -7,10 +12,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 76346dc..29f8c19 100644 --- a/examples/terminal/webpack.config.js +++ b/examples/terminal/webpack.config.js @@ -1,4 +1,10 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: ['whatwg-fetch', './build/index.js'], @@ -12,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()) } }, { @@ -28,20 +34,16 @@ 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: () => '/' } }) diff --git a/examples/test_examples.py b/examples/test_examples.py index 12c624b..583bda5 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -1,11 +1,13 @@ - # -*- 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 @@ -17,47 +19,46 @@ here = osp.abspath(osp.dirname(__file__)) + def header(path): test_name = osp.basename(path) - print('\n'.join(( - '\n', - '*' * 40, - 'Starting %s test in %s' % (test_name, path), - '*' * 40 - )), flush=True) + print( + "\n".join(("\n", "*" * 40, "Starting %s test in %s" % (test_name, path), "*" * 40)), + flush=True, + ) + def main(): parser = argparse.ArgumentParser() parser.add_argument("--testPath", help="paths containing this string are tested") args = parser.parse_args() - paths = [i for i in glob.glob('%s/*' % here) if osp.isdir(i)] + 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)] + services_dir = osp.abspath(osp.join(here, "../packages/services/examples")) + paths += [i for i in glob.glob("%s/*" % services_dir)] if args.testPath: paths = [p for p in paths if args.testPath in p] - print('Testing %s'%paths) + print("Testing %s" % paths) count = 0 for path in sorted(paths): - if osp.basename(path) == 'node': + if osp.basename(path) == "node": with tempfile.TemporaryDirectory() as cwd: header(path) - runner = osp.join(path, 'main.py') + runner = osp.join(path, "main.py") subprocess.check_call([sys.executable, runner], cwd=cwd) count += 1 - elif osp.exists(osp.join(path, 'main.py')): + elif osp.exists(osp.join(path, "main.py")): with tempfile.TemporaryDirectory() as cwd: header(path) - runner = osp.join(here, 'example_check.py') + runner = osp.join(here, "example_check.py") subprocess.check_call([sys.executable, runner, path], cwd=cwd) count += 1 - print('\n\n%s tests complete!' % count) + print("\n\n%s tests complete!" % count) if __name__ == "__main__": main() - diff --git a/galata/README.md b/galata/README.md index 7d12965..c22fc44 100644 --- a/galata/README.md +++ b/galata/README.md @@ -35,8 +35,7 @@ module.exports = require('@jupyterlab/galata/lib/playwright-config'); Create `ui-tests/foo.spec.ts` to define your test. ```typescript -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, test } from '@jupyterlab/galata'; test.describe('Notebook Tests', () => { test('Create New Notebook', async ({ page, tmpPath }) => { @@ -133,6 +132,88 @@ jupyter lab --config jupyter_server_test_config.py & PWDEBUG=1 jlpm playwright test ``` +### Dealing with login + +If you have set up a custom login handler for your Jupyter application and don't want to remove it +for your integration tests, you can try the following configuration (inspired by the +[Playwright documentation](https://playwright.dev/docs/test-advanced#global-setup-and-teardown)): + +1. Create a file named `global-setup.ts` at the root of the test folder containing the login steps: + +```typescript +// global-setup.ts + +import { chromium, FullConfig } from '@playwright/test'; + +async function globalSetup(config: FullConfig) { + const { baseURL, storageState } = config.projects[0].use; + const browser = await chromium.launch(); + const page = await browser.newPage(); + + // Here follows the step to log in if you setup a known password + // See the server documentation https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html?#automatic-password-setup + await page.goto(baseURL ?? process.env.TARGET_URL ?? 'http://localhost:8888/'); + await page.locator('input[name="password"]').fill('test'); + await page.locator('text=Log in').click(); + + // Save signed-in state. + await page.context().storageState({ path: storageState as string }); + await browser.close(); +} + +export default globalSetup; +``` + +2. Modify the Playwright configuration file to use that global setup and the stored state: + +```typescript +var baseConfig = require('@jupyterlab/galata/lib/playwright-config'); + +module.exports = { + ...baseConfig, + globalSetup: require.resolve('./global-setup'), + use: { + ...baseConfig.use, + // Tell all tests to load signed-in state from 'storageState.json'. + storageState: 'storageState.json' + } +}; +``` + +When you will start your test, a file named `storageStage.json` will be generated if the log in +steps were successful. Its content will look like that: + +```json +{ + "cookies": [ + { + "name": "_xsrf", + "value": "...REDACTED...", + "domain": "localhost", + "path": "/", + "expires": -1, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "username-localhost-8888", + "value": "...REDACTED...", + "domain": "localhost", + "path": "/", + "expires": 1664121119.118241, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + } + ], + "origins": [] +} +``` + +> 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. + ## Fixtures Here are the new test fixture introduced by Galata on top of [Playwright fixtures](https://playwright.dev/docs/api/class-fixtures). @@ -168,8 +249,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(); @@ -396,7 +476,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 @@ -413,11 +493,11 @@ A special report will be generated in the folder `benchmark-results` that will c - `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_](https://vega.github.io/vega-lite) description used to produce the PNG file. +- `lab-benchmark.svg`: A comparison of execution time distribution +- `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 @@ -425,7 +505,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/jupyter_server_test_config.py b/galata/jupyter_server_test_config.py index 4cdee40..20132f4 100644 --- a/galata/jupyter_server_test_config.py +++ b/galata/jupyter_server_test_config.py @@ -1,4 +1,8 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + import getpass +import os from tempfile import mkdtemp # Test if we are running in a docker @@ -10,8 +14,11 @@ c.ServerApp.open_browser = False c.LabApp.dev_mode = True -c.ServerApp.root_dir = mkdtemp(prefix='galata-test-') +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 + +# 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 5da313b..42982e5 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 eed3ef3..9a16809 100644 --- a/galata/package.json +++ b/galata/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/galata", - "version": "4.2.2", + "version": "5.0.0-alpha.12", "description": "JupyterLab UI Testing Framework", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -29,33 +29,36 @@ "style/index.js" ], "scripts": { - "build": "jlpm run clean && jlpm run build:galata && jlpm run build:inpage", + "build": "npm run clean && npm run build:galata && npm run build:inpage", "build:all": "npm run build", "build:galata": "tsc -b", "build:inpage": "webpack --mode=production", "clean": "rimraf lib tsconfig.tsbuildinfo", "start": "jupyter lab --config ./jupyter_server_test_config.py", - "start:detached": "(jlpm run start&)", + "start:detached": "(npm run start&)", + "start:doc": "jupyter lab --config ./jupyter_server_test_config.py --extensions-in-dev-mode", "test": "playwright test", "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:report": "http-server ./playwright-report -a localhost -o", - "test:update": "playwright test --update-snapshots" + "test:doc": "jlpm run test -c playwright-documentation.config.js", + "test:doc:update": "jlpm run test -c playwright-documentation.config.js --update-snapshots", + "test:report": "playwright show-report", + "test:update": "playwright test --update-snapshots && jlpm test:benchmark:update" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/cells": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docmanager": "^3.3.2", - "@jupyterlab/nbformat": "^3.3.2", - "@jupyterlab/notebook": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/settingregistry": "^3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/coreutils": "^1.5.3", - "@playwright/test": "^1.16.2", - "@stdlib/stats": "^0.0.13", - "canvas": "^2.6.1", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/cells": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.12", + "@jupyterlab/nbformat": "^4.0.0-alpha.12", + "@jupyterlab/notebook": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/coreutils": "^1.12.0", + "@playwright/test": "^1.17.0", + "@stdlib/stats": "~0.0.13", "fs-extra": "^9.0.1", "http-server": "^13.0.0", "json5": "^2.1.1", @@ -68,19 +71,16 @@ }, "devDependencies": { "@types/node-fetch": "^2.5.4", - "css-loader": "^5.0.1", - "file-loader": "~6.0.0", - "raw-loader": "~4.0.0", + "css-loader": "^6.7.1", + "mini-svg-data-uri": "^1.4.4", "rimraf": "~3.0.0", "source-map-loader": "~1.0.2", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", + "style-loader": "~3.3.1", "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" + "ts-loader": "^9.3.0", + "typescript": "~4.7.3", + "webpack": "^5.72.0", + "webpack-cli": "^4.9.2" }, "publishConfig": { "access": "public" diff --git a/galata/playwright-documentation.config.js b/galata/playwright-documentation.config.js new file mode 100644 index 0000000..9241f91 --- /dev/null +++ b/galata/playwright-documentation.config.js @@ -0,0 +1,26 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +var baseConfig = require('@jupyterlab/galata/lib/playwright-config'); + +module.exports = { + ...baseConfig, + timeout: 90000, + projects: [ + { + name: 'documentation', + testMatch: 'test/documentation/**' + } + ], + use: { + ...baseConfig.use, + launchOptions: { + // Force slow motion + slowMo: 30 + } + }, + // 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: process.env.CI ? 2 : 0 +}; diff --git a/galata/playwright.config.js b/galata/playwright.config.js index 4eed50f..7aa0d59 100644 --- a/galata/playwright.config.js +++ b/galata/playwright.config.js @@ -18,5 +18,5 @@ module.exports = { // 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 aa9eac8..b5b081c 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 { @@ -9,7 +14,6 @@ import { TestResult } from '@playwright/test/reporter'; import { dists, meanpw, variancepn } from '@stdlib/stats/base'; -import * as canvas from 'canvas'; import fs from 'fs'; import path from 'path'; import si from 'systeminformation'; @@ -340,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; @@ -382,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 }; }) ); @@ -430,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 }; @@ -451,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}` @@ -468,25 +476,11 @@ class BenchmarkReporter implements Reporter { const vegaSpec = vl.compile(config as any).spec; const view = new vega.View(vega.parse(vegaSpec), { - renderer: 'canvas' + renderer: 'svg' }).initialize(); - const canvas = ((await view.toCanvas()) as any) as canvas.Canvas; - const graphFile = path.resolve(outputDir, `${baseName}.png`); - const fileStream = fs.createWriteStream(graphFile); - - // Wait for pipe operation to finish - let resolver: (v: unknown) => void; - const waitForPipe = new Promise(resolve => { - resolver = resolve; - }); - fileStream.once('finish', () => { - resolver(void 0); - }); - - const stream = canvas.createPNGStream(); - stream.pipe(fileStream, {}); - - await waitForPipe; + const svgFigure = await view.toSVG(); + const graphFile = path.resolve(outputDir, `${baseName}.svg`); + fs.writeFileSync(graphFile, svgFigure); } else { console.log(reportString); } @@ -501,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( @@ -554,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( @@ -578,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++; } @@ -589,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); @@ -603,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; @@ -676,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, @@ -744,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 fcf2eeb..2e2b8c9 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 72f7d8d..fd7790d 100644 --- a/galata/src/contents.ts +++ b/galata/src/contents.ts @@ -4,7 +4,7 @@ import { URLExt } from '@jupyterlab/coreutils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { Contents } from '@jupyterlab/services'; -import { Page } from '@playwright/test'; +import { APIRequestContext, APIResponse, Page } from '@playwright/test'; import fetch, { RequestInit, Response } from 'node-fetch'; import * as path from 'path'; import { @@ -26,8 +26,19 @@ export class ContentsHelper { * * @param baseURL Server base URL * @param page Playwright page model object + * @param request Playwright API request context */ - constructor(readonly baseURL: string, readonly page?: Page) {} + constructor( + readonly baseURL: string, + readonly page?: Page, + request?: APIRequestContext + ) { + if (request) { + this.request = request; + } else if (page) { + this.request = page.context().request; + } + } /** * Return the model for a path. @@ -40,36 +51,24 @@ export class ContentsHelper { path: string, type: 'file' | 'directory' = 'file' ): Promise { - const baseUrl = this.page ? await Utils.getBaseUrl(this.page) : '/'; - const token = this.page ? await Utils.getToken(this.page) : ''; - const apiUrl = `${this.baseURL}${baseUrl}api/contents`; - const data = { type, // Get the content only for directory content: type === 'directory' ? 1 : 0 }; - const request: RequestInit = { - method: 'GET' - }; - - if (token) { - request.headers = { Authorization: `Token ${token}` }; - } - - let response: Response | null = null; + let response = null; try { - response = await fetch( - `${apiUrl}/${path}` + URLExt.objectToQueryString(data), - request - ); + response = await this._fetch(path + URLExt.objectToQueryString(data)); } catch (error) { console.error(`Fail to get content metadata for ${path}`, error); } - const succeeded = response?.status === 200; + const succeeded = + (typeof response?.status === 'function' + ? response.status() + : response?.status) === 200; if (succeeded) { return response!.json(); @@ -180,7 +179,7 @@ export class ContentsHelper { type: 'file' }); - let response: Response | null = null; + let response = null; try { response = await this._fetch(destinationPath, { @@ -194,7 +193,10 @@ export class ContentsHelper { ); } - const succeeded = response?.status === 201; + const succeeded = + (typeof response?.status === 'function' + ? response.status() + : response?.status) === 201; if (succeeded) { return await this.fileExists(destinationPath); @@ -232,7 +234,7 @@ export class ContentsHelper { async deleteFile(filePath: string): Promise { const fileName = filePath; - let response: Response | null = null; + let response = null; try { response = await this._fetch(fileName, { @@ -242,7 +244,10 @@ export class ContentsHelper { console.error(`Failed to delete file ${filePath}`, error); } - const succeeded = response?.status === 204; + const succeeded = + (typeof response?.status === 'function' + ? response.status() + : response?.status) === 204; if (succeeded) { return !(await this.fileExists(fileName)); @@ -313,7 +318,7 @@ export class ContentsHelper { ); } - let response: Response | null = null; + let response = null; try { response = await this._fetch(oldName, { @@ -324,7 +329,10 @@ export class ContentsHelper { console.error(`Failed to rename file ${oldName} to ${newName}`, error); } - const succeeded = response?.status === 200; + const succeeded = + (typeof response?.status === 'function' + ? response.status() + : response?.status) === 200; if (succeeded) { return await this.fileExists(newName); @@ -381,25 +389,38 @@ export class ContentsHelper { console.error(`Failed to create directory ${dirPath}`, error); } - return response?.status === 201; + return ( + (typeof response?.status === 'function' + ? response.status() + : response?.status) === 201 + ); } private async _fetch( path: string, request: RequestInit = { method: 'GET' } - ): Promise { + ): Promise { const baseUrl = this.page ? await Utils.getBaseUrl(this.page) : '/'; const token = this.page ? await Utils.getToken(this.page) : ''; - const url = URLExt.join(this.baseURL, baseUrl, 'api/contents', path); + let url = URLExt.join(baseUrl, 'api/contents', path); if (token) { request.headers = { Authorization: `Token ${token}` }; } - let response: Response | null = null; + let response: APIResponse | Response | null = null; - response = await fetch(url, request); + if (this.request) { + response = await this.request.fetch(url, { + ...(request as any), + data: request.body + }); + } else { + response = await fetch(url, request); + } return response; } + + readonly request: APIRequestContext | null = null; } diff --git a/galata/src/fixtures.ts b/galata/src/fixtures.ts index 56d0e9b..7d029a9 100644 --- a/galata/src/fixtures.ts +++ b/galata/src/fixtures.ts @@ -12,6 +12,7 @@ import { PlaywrightWorkerOptions, TestType } from '@playwright/test'; +import * as path from 'path'; import { ContentsHelper } from './contents'; import { galata } from './galata'; import { IJupyterLabPage, IJupyterLabPageFixture } from './jupyterlabpage'; @@ -55,16 +56,6 @@ export type GalataOptions = { * Default: true */ autoGoto: boolean; - /** - * Galata can keep the uploaded and created files in ``tmpPath`` on - * the server root for debugging purpose. By default the files are - * always deleted - * - * - 'off' - ``tmpPath`` is deleted after each tests - * - 'on' - ``tmpPath`` is never deleted - * - 'only-on-failure' - ``tmpPath`` is deleted except if a test failed or timed out. - */ - serverFiles: 'on' | 'off' | 'only-on-failure'; /** * Mock JupyterLab state in-memory or not. * @@ -90,6 +81,16 @@ export type GalataOptions = { * they are still initialized with the hard drive values. */ mockSettings: boolean | Record; + /** + * Galata can keep the uploaded and created files in ``tmpPath`` on + * the server root for debugging purpose. By default the files are + * always deleted + * + * - 'off' - ``tmpPath`` is deleted after each tests + * - 'on' - ``tmpPath`` is never deleted + * - 'only-on-failure' - ``tmpPath`` is deleted except if a test failed or timed out. + */ + serverFiles: 'on' | 'off' | 'only-on-failure'; /** * Sessions created during the test. * @@ -118,7 +119,7 @@ export type GalataOptions = { */ tmpPath: string; /** - * Wait for the application page to be ready + * Wait for the application page to be ready. * * @param page Playwright Page model * @param helpers JupyterLab helpers @@ -242,12 +243,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 }, use, testInfo) => { - const parts = testInfo.outputDir.split('/'); + tmpPath: async ({ baseURL, serverFiles, request }, use, testInfo) => { // Remove appended retry part for reproducibility - const testFolder = parts[parts.length - 1].replace(/-retry\d+$/i, ''); + const testFolder = path + .basename(testInfo.outputDir) + .replace(/-retry\d+$/i, ''); - const contents = new ContentsHelper(baseURL!); + const contents = new ContentsHelper(baseURL!, undefined, request); if (await contents.directoryExists(testFolder)) { await contents.deleteDirectory(testFolder); @@ -274,7 +276,7 @@ export const test: TestType< * @param page Playwright Page model * @param helpers JupyterLab helpers */ - waitForApplication: async ({ baseURL }, use, testInfo) => { + waitForApplication: async ({ baseURL }, use) => { const waitIsReady = async ( page: Page, helpers: IJupyterLabPage diff --git a/galata/src/galata.ts b/galata/src/galata.ts index 22d46cb..1dc3bf7 100644 --- a/galata/src/galata.ts +++ b/galata/src/galata.ts @@ -5,7 +5,7 @@ import * as nbformat from '@jupyterlab/nbformat'; import { Session, TerminalAPI, Workspace } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { Browser, Page } from '@playwright/test'; +import { APIRequestContext, Browser, Page } from '@playwright/test'; import * as json5 from 'json5'; import fetch from 'node-fetch'; import { ContentsHelper } from './contents'; @@ -35,6 +35,14 @@ export namespace galata { } }; + export const DEFAULT_DOCUMENTATION_STATE: Record = { + data: { + 'layout-restorer:data': { + relativeSizes: [0, 1, 0] + } + } + }; + /** * Sidebar position */ @@ -177,13 +185,15 @@ export namespace galata { * * @param baseURL Application base URL * @param page Playwright page model + * @param request Playwright API request context * @returns Contents REST API helpers */ export function newContentsHelper( baseURL: string, - page?: Page + page?: Page, + request?: APIRequestContext ): ContentsHelper { - return new ContentsHelper(baseURL, page); + return new ContentsHelper(baseURL, page, request); } /** @@ -238,12 +248,27 @@ export namespace galata { * Regex to capture JupyterLab API call */ export namespace Routes { + /** + * Contents API + * + * The content path can be found in the named group `path`. + * + * The path will be prefixed by '/'. + * The path will be undefined for the root folder. + */ + export const contents = /.*\/api\/contents(?\/.+)?\?/; + + /** + * Extensions API + */ + export const extensions = /.*\/lab\/api\/extensions/; + /** * Sessions API * * 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]+)?/; @@ -252,7 +277,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]+)*)/; @@ -261,7 +286,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]+)?/; @@ -270,7 +295,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]+)?/; @@ -279,7 +304,7 @@ 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]+)+)/; } @@ -395,25 +420,96 @@ 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.on('close', () => { + isClosed = true; + }); + ctxt.browser()?.on('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. * * @param baseURL Application base URL * @param runners Session or terminal ids to stop * @param type Type of runner; session or terminal + * @param request API request context * @returns Whether the runners were closed or not */ export async function clearRunners( baseURL: string, runners: string[], - type: 'sessions' | 'terminals' + type: 'sessions' | 'terminals', + request?: APIRequestContext ): Promise { const responses = await Promise.all( [...new Set(runners)].map(id => - fetch(`${baseURL}/api/${type}/${id}`, { method: 'DELETE' }) + request + ? request.fetch(`/api/${type}/${id}`, { + method: 'DELETE' + }) + : fetch(`${baseURL}/api/${type}/${id}`, { method: 'DELETE' }) ) ); - return responses.every(response => response.ok); + return responses.every(response => + typeof response.ok === 'function' ? response.ok() : response.ok + ); } /** @@ -460,14 +556,11 @@ export namespace galata { if (id) { if (runners.has(id)) { // Proxy the GET request - const response = await fetch(request.url(), { - headers: await request.allHeaders(), - method: request.method() - }); - if (!response.ok) { + const response = await ctxt.request.fetch(request); + if (!response.ok()) { if (!page.isClosed() && !isClosed) { return route.fulfill({ - status: response.status, + status: response.status(), body: await response.text() }); } @@ -495,14 +588,11 @@ export namespace galata { } } else { // Proxy the GET request - const response = await fetch(request.url(), { - headers: await request.allHeaders(), - method: request.method() - }); - if (!response.ok) { + const response = await ctxt.request.fetch(request); + if (!response.ok()) { if (!page.isClosed() && !isClosed) { return route.fulfill({ - status: response.status, + status: response.status(), body: await response.text() }); } @@ -539,15 +629,11 @@ export namespace galata { } case 'PATCH': { // Proxy the PATCH request - const response = await fetch(request.url(), { - body: request.postDataBuffer()!, - headers: await request.allHeaders(), - method: request.method() - }); - if (!response.ok) { + const response = await ctxt.request.fetch(request); + if (!response.ok()) { if (!page.isClosed() && !isClosed) { return route.fulfill({ - status: response.status, + status: response.status(), body: await response.text() }); } @@ -568,15 +654,11 @@ export namespace galata { } case 'POST': { // Proxy the POST request - const response = await fetch(request.url(), { - body: request.postDataBuffer()!, - headers: await request.allHeaders(), - method: request.method() - }); - if (!response.ok) { + const response = await ctxt.request.fetch(request); + if (!response.ok()) { if (!page.isClosed() && !isClosed) { return route.fulfill({ - status: response.status, + status: response.status(), body: await response.text() }); } @@ -666,9 +748,7 @@ export namespace galata { if (!id) { // Get all settings if (settings.length === 0) { - const response = await fetch(request.url(), { - headers: await request.allHeaders() - }); + const response = await ctxt.request.fetch(request); const loadedSettings = (await response.json()) .settings as ISettingRegistry.IPlugin[]; @@ -694,9 +774,7 @@ export namespace galata { // Get specific settings let pluginSettings = settings.find(setting => setting.id === id); if (!pluginSettings) { - const response = await fetch(request.url(), { - headers: await request.allHeaders() - }); + const response = await ctxt.request.fetch(request); pluginSettings = await response.json(); if (pluginSettings) { const mocked = mockedSettings[id] ?? {}; diff --git a/galata/src/helpers/debuggerpanel.ts b/galata/src/helpers/debuggerpanel.ts new file mode 100644 index 0000000..feff497 --- /dev/null +++ b/galata/src/helpers/debuggerpanel.ts @@ -0,0 +1,146 @@ +/* + * 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'); + } + + /** + * 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 d877011..5e7a871 100644 --- a/galata/src/helpers/filebrowser.ts +++ b/galata/src/helpers/filebrowser.ts @@ -136,6 +136,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 67b014b..abbcae2 100644 --- a/galata/src/helpers/index.ts +++ b/galata/src/helpers/index.ts @@ -11,3 +11,4 @@ export * from './performance'; export * from './sidebar'; export * from './statusbar'; export * from './theme'; +export * from './debuggerpanel'; diff --git a/galata/src/helpers/notebook.ts b/galata/src/helpers/notebook.ts index 8a87e9c..6ec2f6b 100644 --- a/galata/src/helpers/notebook.ts +++ b/galata/src/helpers/notebook.ts @@ -116,7 +116,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; @@ -704,6 +704,113 @@ 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(); + 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 * @@ -778,11 +885,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); } diff --git a/galata/src/helpers/sidebar.ts b/galata/src/helpers/sidebar.ts index f7922e3..229550a 100644 --- a/galata/src/helpers/sidebar.ts +++ b/galata/src/helpers/sidebar.ts @@ -140,16 +140,23 @@ export class SidebarHelper { const settingRegistry = (await window.galataip.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: 'right', + '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 } ); diff --git a/galata/src/index.ts b/galata/src/index.ts index ab51da0..2706959 100644 --- a/galata/src/index.ts +++ b/galata/src/index.ts @@ -6,6 +6,11 @@ * @module galata */ +/** + * Export expect from playwright to simplify the import in tests + */ +export { expect } from '@playwright/test'; + export * from './benchmarkReporter'; export * from './galata'; export * from './global'; diff --git a/galata/src/inpage/index.ts b/galata/src/inpage/index.ts index 4c82be3..3f50ce7 100644 --- a/galata/src/inpage/index.ts +++ b/galata/src/inpage/index.ts @@ -137,7 +137,7 @@ export class GalataInpage implements IGalataInpage { * * @param path Path to monitor */ - async waitForLaunch(path = '/lab'): Promise { + async waitForLaunch(path = '/doc'): Promise { let resolver: () => void; const delegate = new Promise(resolve => { resolver = resolve; diff --git a/galata/src/inpage/tokens.ts b/galata/src/inpage/tokens.ts index 7a37c7d..8a914cb 100644 --- a/galata/src/inpage/tokens.ts +++ b/galata/src/inpage/tokens.ts @@ -1,9 +1,10 @@ // Copyright (c) Bloomberg Finance LP. // Distributed under the terms of the Modified BSD License. -import { IRouter, JupyterFrontEnd } from '@jupyterlab/application'; -import { IDocumentManager } from '@jupyterlab/docmanager'; -import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { JupyterFrontEnd } from '@jupyterlab/application'; +import type { IRouter } from '@jupyterlab/application'; +import type { IDocumentManager } from '@jupyterlab/docmanager'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; /** * Cell execution callbacks interface @@ -34,7 +35,7 @@ export interface IWaitForSelectorOptions { } export const PLUGIN_ID_ROUTER = '@jupyterlab/application-extension:router'; -export const PLUGIN_ID_DOC_MANAGER = '@jupyterlab/docmanager-extension:plugin'; +export const PLUGIN_ID_DOC_MANAGER = '@jupyterlab/docmanager-extension:manager'; export const PLUGIN_ID_SETTINGS = '@jupyterlab/apputils-extension:settings'; export interface IPluginNameToInterfaceMap { diff --git a/galata/src/jupyterlabpage.ts b/galata/src/jupyterlabpage.ts index d90c417..2f617b8 100644 --- a/galata/src/jupyterlabpage.ts +++ b/galata/src/jupyterlabpage.ts @@ -1,11 +1,13 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; import type { ElementHandle, Page, Response } from '@playwright/test'; import * as path from 'path'; import { ContentsHelper } from './contents'; import { ActivityHelper, + DebuggerHelper, FileBrowserHelper, KernelHelper, LogConsoleHelper, @@ -16,6 +18,7 @@ import { StatusBarHelper, ThemeHelper } from './helpers'; +import { IPluginNameToInterfaceMap, PLUGIN_ID_SETTINGS } from './inpage/tokens'; import * as Utils from './utils'; /** @@ -84,6 +87,11 @@ export interface IJupyterLabPage { */ readonly launcherSelector: string; + /** + * Debugger helper + */ + readonly debugger: DebuggerHelper; + /** * Getter for JupyterLab base URL */ @@ -186,7 +194,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 @@ -250,11 +258,11 @@ export class JupyterLabPage implements IJupyterLabPage { readonly page: Page, readonly baseURL: string, waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise, - readonly appPath: string = '/lab' + readonly appPath: string = '/doc' ) { this.waitIsReady = waitForApplication; this.activity = new ActivityHelper(page); - this.contents = new ContentsHelper(baseURL, page); + this.contents = new ContentsHelper(baseURL, page, page.context().request); this.filebrowser = new FileBrowserHelper(page, this.contents); this.kernel = new KernelHelper(page); this.logconsole = new LogConsoleHelper(page); @@ -270,6 +278,7 @@ export class JupyterLabPage implements IJupyterLabPage { this.statusbar = new StatusBarHelper(page, this.menu); this.sidebar = new SidebarHelper(page, this.menu); this.theme = new ThemeHelper(page); + this.debugger = new DebuggerHelper(page, this.sidebar, this.notebook); } /** @@ -326,6 +335,11 @@ export class JupyterLabPage implements IJupyterLabPage { */ readonly theme: ThemeHelper; + /** + * JupyterLab debugger helper + */ + readonly debugger: DebuggerHelper; + /** * Selector for launcher tab */ @@ -478,16 +492,26 @@ export class JupyterLabPage implements 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'; + + /** + * Whether to wait for fixture `waitIsReady` or not when reloading. + * + * Default is true. + */ + waitForIsReady?: boolean; }): Promise { const response = await this.page.reload({ - ...(options ?? {}), + timeout: options?.timeout, waitUntil: options?.waitUntil ?? 'domcontentloaded' }); await this.waitForAppStarted(); await this.hookHelpersUp(); - await this.waitIsReady(this.page, this); + if (options?.waitForIsReady ?? true) { + await this.waitIsReady(this.page, this); + } return response; } @@ -503,8 +527,17 @@ 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.galataip.getPlugin( + pluginId + )) as ISettingRegistry; + const SHELL_ID = '@jupyterlab/application-extension:shell'; + await settingRegistry.remove(SHELL_ID, 'layout'); + }, + { pluginId: PLUGIN_ID_SETTINGS as keyof IPluginNameToInterfaceMap } + ); // show Files tab on sidebar await this.sidebar.openTab('filebrowser'); // go to home folder diff --git a/galata/src/playwright-config.ts b/galata/src/playwright-config.ts index 13bfda5..28bdc54 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 ? 'dot' : 'list'], + ['html', { open: process.env.CI ? 'never' : 'on-failure' }] + ], reportSlowTests: null, timeout: 60000, use: { diff --git a/galata/src/vega-statistics.d.ts b/galata/src/vega-statistics.d.ts index b335f5e..dd70ea0 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 a311a59..6351d9e 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 }) => { - const content = galata.newContentsHelper(baseURL); + test.beforeAll(async ({ baseURL, request }) => { + const content = galata.newContentsHelper(baseURL, undefined, request); const codeContent = galata.Notebook.generateNotebook(300, 'code', [ 'for x in range(OUTPUT_LENGTH):\n', ' print(f"{PREFIX} {x}")' @@ -75,8 +75,8 @@ test.describe('Benchmark', () => { }); // Remove benchmark files - test.afterAll(async ({ baseURL }) => { - const content = galata.newContentsHelper(baseURL); + test.afterAll(async ({ baseURL, request }) => { + const content = galata.newContentsHelper(baseURL, undefined, request); await content.deleteDirectory(tmpPath); }); @@ -137,7 +137,7 @@ 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('button:has-text("Shut Down All") >> nth=-1'); // Click on the last matched button. // Open text file const fromTime = await perf.measure(async () => { 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 375fe84..99728f7 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 5b5e367..cb1a9e5 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 0000000..327999b --- /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 0000000..52f1a48 --- /dev/null +++ b/galata/test/documentation/commands.test.ts-snapshots/commandsList-documentation-linux.json @@ -0,0 +1,2153 @@ +[ + { + "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:incr-font-size", + "label": "Increase Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "apputils:load-statedb", + "label": "Load state for the current workspace.", + "caption": "", + "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": "code-viewer:open", + "label": "Open Code Viewer", + "caption": "", + "shortcuts": [] + }, + { + "id": "codemirror:change-keymap", + "label": "default", + "caption": "", + "shortcuts": [] + }, + { + "id": "codemirror:change-mode", + "label": "Change editor mode to the provided `name`.", + "caption": "", + "shortcuts": [] + }, + { + "id": "codemirror:change-theme", + "label": "jupyter", + "caption": "", + "shortcuts": [] + }, + { + "id": "codemirror:find", + "label": "Findâ€Ļ", + "caption": "", + "shortcuts": [] + }, + { + "id": "codemirror:go-to-line", + "label": "Go to Lineâ€Ļ", + "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": "Continue", + "caption": "Continue", + "shortcuts": [ + "F9" + ] + }, + { + "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", + "label": "Enable / Disable pausing on exceptions", + "caption": "Enable / Disable pausing on exceptions", + "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: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": "editmenu:clear-all", + "label": "Clear All", + "caption": "Clear All", + "shortcuts": [] + }, + { + "id": "editmenu:clear-current", + "label": "Clear", + "caption": "Clear", + "shortcuts": [] + }, + { + "id": "editmenu:go-to-line", + "label": "Go to Lineâ€Ļ", + "caption": "Go to Lineâ€Ļ", + "shortcuts": [] + }, + { + "id": "editmenu:open", + "label": "Open Edit Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "editmenu:redo", + "label": "Redo", + "caption": "Redo", + "shortcuts": [ + "Ctrl Shift Z" + ] + }, + { + "id": "editmenu:undo", + "label": "Undo", + "caption": "Undo", + "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-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": "fileeditor:change-font-size", + "label": "Decrease Font Size", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:change-tabs", + "label": "Indent with Tab", + "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: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 for 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": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-current-line-wrap", + "label": "Wrap Words", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-current-match-brackets", + "label": "Match Brackets", + "caption": "", + "shortcuts": [] + }, + { + "id": "fileeditor:toggle-line-numbers", + "label": "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": "Close and Shut Down", + "shortcuts": [ + "Ctrl Shift Q" + ] + }, + { + "id": "filemenu:create-console", + "label": "New Console for Activity", + "caption": "New Console for Activity", + "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": "Get Kernel", + "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": "Change Kernelâ€Ļ", + "shortcuts": [] + }, + { + "id": "kernelmenu:interrupt", + "label": "Interrupt Kernel", + "caption": "Interrupt Kernel", + "shortcuts": [ + "I", + "I" + ] + }, + { + "id": "kernelmenu:open", + "label": "Open Kernel Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "kernelmenu:reconnect-to-kernel", + "label": "Reconnect to Kernel", + "caption": "Reconnect to Kernel", + "shortcuts": [] + }, + { + "id": "kernelmenu:restart", + "label": "Restart Kernelâ€Ļ", + "caption": "Restart Kernelâ€Ļ", + "shortcuts": [ + "0", + "0" + ] + }, + { + "id": "kernelmenu:restart-and-clear", + "label": "Restart Kernel and Clearâ€Ļ", + "caption": "Restart Kernel and Clearâ€Ļ", + "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": "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 Cells", + "caption": "Copy the selected cells", + "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 Cells", + "caption": "Cut the selected cells", + "shortcuts": [ + "X" + ] + }, + { + "id": "notebook:delete-cell", + "label": "Delete Cells", + "caption": "", + "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 Cells Below", + "caption": "Copy the selected cells and paste them below the selection", + "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": "", + "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": "", + "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 Cells Down", + "caption": "", + "shortcuts": [ + "Ctrl Shift ArrowDown" + ] + }, + { + "id": "notebook:move-cell-up", + "label": "Move Cells Up", + "caption": "", + "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 Cells and Replace", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:paste-cell-above", + "label": "Paste Cells Above", + "caption": "", + "shortcuts": [] + }, + { + "id": "notebook:paste-cell-below", + "label": "Paste Cells Below", + "caption": "Paste cells 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": "", + "shortcuts": [] + }, + { + "id": "notebook:restart-run-all", + "label": "Restart Kernel and Run All Cellsâ€Ļ", + "caption": "", + "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": "", + "shortcuts": [] + }, + { + "id": "notebook:run-cell", + "label": "Run Selected Cells and Don't Advance", + "caption": "", + "shortcuts": [ + "Ctrl Enter" + ] + }, + { + "id": "notebook:run-cell-and-insert-below", + "label": "Run Selected Cells and Insert Below", + "caption": "", + "shortcuts": [ + "Alt Enter" + ] + }, + { + "id": "notebook:run-cell-and-select-next", + "label": "Run Selected Cells", + "caption": "", + "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: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: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: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": "Show Line Numbers", + "shortcuts": [] + }, + { + "id": "viewmenu:match-brackets", + "label": "Match Brackets", + "caption": "Match Brackets", + "shortcuts": [] + }, + { + "id": "viewmenu:open", + "label": "Open View Menu", + "caption": "", + "shortcuts": [] + }, + { + "id": "viewmenu:word-wrap", + "label": "Wrap Words", + "caption": "Wrap Words", + "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 0000000..ad802c5 --- /dev/null +++ b/galata/test/documentation/customization.test.ts @@ -0,0 +1,272 @@ +// 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'); + + await page.waitForSelector('text=Python 3 (ipykernel) | Idle'); + + 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'); + + 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'); + await page.pause(); + 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 0000000..b4a5328 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 0000000..ea5f429 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 0000000..5c1b553 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 0000000..85a9fe9 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 0000000..d151252 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 0000000..3ca398e 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 0000000..58979cf 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 0000000..a93095c 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 0000000..8729baa --- /dev/null +++ b/galata/test/documentation/data/extensions-search-all.json @@ -0,0 +1,202 @@ +{ + "objects": [ + { + "package": { + "name": "@jupyterlab/apputils", + "scope": "jupyterlab", + "version": "3.4.4", + "description": "JupyterLab - Application Utilities", + "keywords": ["jupyter", "jupyterlab", "jupyterlab-extension"], + "date": "2022-07-21T14:47:49.450Z", + "links": { + "npm": "https://www.npmjs.com/package/%40jupyterlab%2Fapputils", + "homepage": "https://github.com/jupyterlab/jupyterlab", + "repository": "https://github.com/jupyterlab/jupyterlab", + "bugs": "https://github.com/jupyterlab/jupyterlab/issues" + }, + "author": { "name": "Project Jupyter" }, + "publisher": { + "username": "fcdoe", + "email": "placeholder@example.com" + }, + "maintainers": [ + { "username": "3cdoe", "email": "placeholder@example.com" }, + { "username": "jwdoe", "email": "placeholder@example.com" }, + { "username": "krdoe", "email": "placeholder@example.com" }, + { "username": "dadoe", "email": "placeholder@example.com" }, + { "username": "dedoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "zudoe", "email": "placeholder@example.com" }, + { "username": "eldoe", "email": "placeholder@example.com" }, + { "username": "bldoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "sydoe", "email": "placeholder@example.com" }, + { "username": "iadoe", "email": "placeholder@example.com" }, + { "username": "gndoe", "email": "placeholder@example.com" }, + { "username": "padoe", "email": "placeholder@example.com" }, + { "username": "mpdoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "midoe", "email": "placeholder@example.com" }, + { "username": "sadoe", "email": "placeholder@example.com" }, + { "username": "hodoe", "email": "placeholder@example.com" }, + { "username": "zsdoe", "email": "placeholder@example.com" }, + { "username": "tedoe", "email": "placeholder@example.com" }, + { "username": "fcdoe", "email": "placeholder@example.com" }, + { "username": "lrdoe", "email": "placeholder@example.com" }, + { "username": "codoe", "email": "placeholder@example.com" }, + { "username": "ajdoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "jtdoe", "email": "placeholder@example.com" }, + { "username": "ecdoe", "email": "placeholder@example.com" }, + { "username": "godoe", "email": "placeholder@example.com" }, + { "username": "mbdoe", "email": "placeholder@example.com" }, + { "username": "lodoe", "email": "placeholder@example.com" } + ] + }, + "score": { + "final": 0.3189719547427941, + "detail": { + "quality": 0.4344936230693638, + "popularity": 0.20559200330090951, + "maintenance": 0.3333333333333333 + } + }, + "searchScore": 9.516456e-8 + }, + { + "package": { + "name": "@jupyterlab/translation", + "scope": "jupyterlab", + "version": "3.4.4", + "description": "JupyterLab - Translation services", + "keywords": ["jupyter", "jupyterlab", "jupyterlab-extension"], + "date": "2022-07-21T14:51:44.592Z", + "links": { + "npm": "https://www.npmjs.com/package/%40jupyterlab%2Ftranslation", + "homepage": "https://github.com/jupyterlab/jupyterlab", + "repository": "https://github.com/jupyterlab/jupyterlab", + "bugs": "https://github.com/jupyterlab/jupyterlab/issues" + }, + "author": { "name": "Project Jupyter" }, + "publisher": { + "username": "fcdoe", + "email": "placeholder@example.com" + }, + "maintainers": [ + { "username": "3cdoe", "email": "placeholder@example.com" }, + { "username": "jwdoe", "email": "placeholder@example.com" }, + { "username": "krdoe", "email": "placeholder@example.com" }, + { "username": "dadoe", "email": "placeholder@example.com" }, + { "username": "dedoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "zudoe", "email": "placeholder@example.com" }, + { "username": "eldoe", "email": "placeholder@example.com" }, + { "username": "bldoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "sydoe", "email": "placeholder@example.com" }, + { "username": "iadoe", "email": "placeholder@example.com" }, + { "username": "gndoe", "email": "placeholder@example.com" }, + { "username": "padoe", "email": "placeholder@example.com" }, + { "username": "mpdoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "midoe", "email": "placeholder@example.com" }, + { "username": "sadoe", "email": "placeholder@example.com" }, + { "username": "hodoe", "email": "placeholder@example.com" }, + { "username": "zsdoe", "email": "placeholder@example.com" }, + { "username": "tedoe", "email": "placeholder@example.com" }, + { "username": "fcdoe", "email": "placeholder@example.com" }, + { "username": "lrdoe", "email": "placeholder@example.com" }, + { "username": "codoe", "email": "placeholder@example.com" }, + { "username": "ajdoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "jtdoe", "email": "placeholder@example.com" }, + { "username": "ecdoe", "email": "placeholder@example.com" }, + { "username": "godoe", "email": "placeholder@example.com" }, + { "username": "mbdoe", "email": "placeholder@example.com" }, + { "username": "lodoe", "email": "placeholder@example.com" } + ] + }, + "score": { + "final": 0.3043979310975364, + "detail": { + "quality": 0.4477368226117161, + "popularity": 0.1526006218495854, + "maintenance": 0.3333333333333333 + } + }, + "searchScore": 3.6817326e-8 + }, + { + "package": { + "name": "@jupyterlab/git", + "scope": "jupyterlab", + "version": "0.37.1", + "description": "A JupyterLab extension for version control using git", + "keywords": [ + "Jupyter", + "JupyterLab", + "JupyterLab3", + "jupyterlab-extension", + "Git" + ], + "date": "2022-04-26T06:32:46.362Z", + "links": { + "npm": "https://www.npmjs.com/package/%40jupyterlab%2Fgit", + "homepage": "https://github.com/jupyterlab/jupyterlab-git", + "repository": "https://github.com/jupyterlab/jupyterlab-git", + "bugs": "https://github.com/jupyterlab/jupyterlab-git/issues" + }, + "author": { "name": "Jupyter Development Team" }, + "publisher": { + "username": "fcdoe", + "email": "placeholder@example.com" + }, + "maintainers": [ + { "username": "3cdoe", "email": "placeholder@example.com" }, + { "username": "jwdoe", "email": "placeholder@example.com" }, + { "username": "krdoe", "email": "placeholder@example.com" }, + { "username": "dadoe", "email": "placeholder@example.com" }, + { "username": "dedoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "zudoe", "email": "placeholder@example.com" }, + { "username": "eldoe", "email": "placeholder@example.com" }, + { "username": "bldoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "sydoe", "email": "placeholder@example.com" }, + { "username": "iadoe", "email": "placeholder@example.com" }, + { "username": "gndoe", "email": "placeholder@example.com" }, + { "username": "padoe", "email": "placeholder@example.com" }, + { "username": "mpdoe", "email": "placeholder@example.com" }, + { "username": "jadoe", "email": "placeholder@example.com" }, + { "username": "midoe", "email": "placeholder@example.com" }, + { "username": "sadoe", "email": "placeholder@example.com" }, + { "username": "hodoe", "email": "placeholder@example.com" }, + { "username": "zsdoe", "email": "placeholder@example.com" }, + { "username": "tedoe", "email": "placeholder@example.com" }, + { "username": "fcdoe", "email": "placeholder@example.com" }, + { "username": "lrdoe", "email": "placeholder@example.com" }, + { "username": "codoe", "email": "placeholder@example.com" }, + { "username": "ajdoe", "email": "placeholder@example.com" }, + { "username": "madoe", "email": "placeholder@example.com" }, + { "username": "jtdoe", "email": "placeholder@example.com" }, + { "username": "ecdoe", "email": "placeholder@example.com" }, + { "username": "godoe", "email": "placeholder@example.com" }, + { "username": "mbdoe", "email": "placeholder@example.com" }, + { "username": "lodoe", "email": "placeholder@example.com" } + ] + }, + "flags": { "unstable": true }, + "score": { + "final": 0.29652759181361366, + "detail": { + "quality": 0.5405756504548741, + "popularity": 0.05053780002995652, + "maintenance": 0.3333333333333333 + } + }, + "searchScore": 1.2284681e-8 + } + ], + "total": 1043, + "time": "Fri Jul 22 2022 12:23:25 GMT+0000 (Coordinated Universal Time)" +} 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 0000000..094b8ba --- /dev/null +++ b/galata/test/documentation/data/extensions-search-drawio.json @@ -0,0 +1,190 @@ +{ + "objects": [ + { + "package": { + "name": "jupyterlab-drawio", + "scope": "unscoped", + "version": "0.9.0", + "description": "A JupyterLab extension for embedding drawio / mxgraph.", + "keywords": [ + "extension", + "jupyter", + "jupyterlab", + "jupyterlab-extension" + ], + "date": "2021-04-29T10:22:28.814Z", + "links": { + "npm": "https://www.npmjs.com/package/jupyterlab-drawio", + "homepage": "https://github.com/QuantStack/jupyterlab-drawio", + "repository": "https://github.com/wolfv/jupyterlab-drawio", + "bugs": "https://github.com/QuantStack/jupyterlab-drawio/issues" + }, + "author": { + "name": "Wolf Vollprecht" + }, + "publisher": { + "username": "hbdoe", + "email": "placeholder@placeholder.com" + }, + "maintainers": [ + { + "username": "jtdoe", + "email": "placeholder@placeholder.com" + }, + { + "username": "jadoe", + "email": "placeholder@placeholder.com" + }, + { + "username": "sydoe", + "email": "placeholder@placeholder.com" + }, + { + "username": "wodoe", + "email": "placeholder@placeholder.com" + }, + { + "username": "hbdoe", + "email": "placeholder@placeholder.com" + } + ] + }, + "flags": { + "unstable": true + }, + "score": { + "final": 0.34052385756365255, + "detail": { + "quality": 0.7307105352777404, + "popularity": 0.01488181698227634, + "maintenance": 0.3317201743900962 + } + }, + "searchScore": 0.000034432942 + }, + { + "package": { + "name": "@deathbeds/ipydrawio", + "scope": "deathbeds", + "version": "1.2.0", + "description": "A JupyterLab extension for embedding interactive drawio / mxgraph diagrams.", + "keywords": ["jupyter", "jupyterlab", "jupyterlab-extension"], + "date": "2022-01-24T19:11:20.950Z", + "links": { + "npm": "https://www.npmjs.com/package/%40deathbeds%2Fipydrawio", + "homepage": "https://ipydrawio.rtfd.io/", + "repository": "https://github.com/deathbeds/ipydrawio", + "bugs": "https://github.com/deathbeds/ipydrawio/issues" + }, + "author": { + "name": "IPyDrawio Contributors" + }, + "publisher": { + "username": "bodoe", + "email": "placeholder@placeholder.com" + }, + "maintainers": [ + { + "username": "bodoe", + "email": "placeholder@placeholder.com" + } + ] + }, + "score": { + "final": 0.3128486745618167, + "detail": { + "quality": 0.619402165107716, + "popularity": 0.03013403799885858, + "maintenance": 0.332803176371147 + } + }, + "searchScore": 0.0000024371393 + }, + { + "package": { + "name": "@deathbeds/ipydrawio-jupyter-templates", + "scope": "deathbeds", + "version": "1.2.0", + "description": "Jupyter Templates for IPyDrawio", + "keywords": [ + "jupyter", + "jupyterlab", + "jupyterlab-extension", + "ipydrawio" + ], + "date": "2022-01-24T19:11:05.334Z", + "links": { + "npm": "https://www.npmjs.com/package/%40deathbeds%2Fipydrawio-jupyter-templates", + "homepage": "https://ipydrawio.rtfd.io/", + "repository": "https://github.com/deathbeds/ipydrawio", + "bugs": "https://github.com/deathbeds/ipydrawio/issues" + }, + "author": { + "name": "IPyDrawio Contributors" + }, + "publisher": { + "username": "bodoe", + "email": "placeholder@placeholder.com" + }, + "maintainers": [ + { + "username": "bodoe", + "email": "placeholder@placeholder.com" + } + ] + }, + "score": { + "final": 0.2995447525446336, + "detail": { + "quality": 0.619402165107716, + "popularity": 0.004097416295027781, + "maintenance": 0.32082859231159744 + } + }, + "searchScore": 5.121934e-7 + }, + { + "package": { + "name": "@deathbeds/jupyterlab-drawio", + "scope": "deathbeds", + "version": "0.8.0-alpha1", + "description": "A JupyterLab extension for embedding drawio / mxgraph.", + "keywords": ["jupyter", "jupyterlab", "jupyterlab-extension"], + "date": "2020-08-16T20:49:05.709Z", + "links": { + "npm": "https://www.npmjs.com/package/%40deathbeds%2Fjupyterlab-drawio", + "homepage": "https://github.com/deathbeds/jupyterlab-drawio", + "repository": "https://github.com/deathbeds/jupyterlab-drawio", + "bugs": "https://github.com/deathbeds/jupyterlab-drawio/issues" + }, + "author": { + "name": "Dead Pixels Collective" + }, + "publisher": { + "username": "bodoe", + "email": "placeholder@placeholder.com" + }, + "maintainers": [ + { + "username": "bodoe", + "email": "placeholder@placeholder.com" + } + ] + }, + "flags": { + "unstable": true + }, + "score": { + "final": 0.1827061624993528, + "detail": { + "quality": 0.3406222556270111, + "popularity": 0.005075320545946132, + "maintenance": 0.22498035320048096 + } + }, + "searchScore": 6.2371446e-9 + } + ], + "total": 4, + "time": "Fri Jun 17 2022 20:01:02 GMT+0000 (Coordinated Universal Time)" +} diff --git a/galata/test/documentation/data/extensions.json b/galata/test/documentation/data/extensions.json new file mode 100644 index 0000000..69ba7e8 --- /dev/null +++ b/galata/test/documentation/data/extensions.json @@ -0,0 +1,34 @@ +[ + { + "name": "@jupyterlab/geojson-extension", + "description": "GeoJSON renderer for JupyterLab", + "url": "https://github.com/jupyterlab/jupyter-renderers", + "enabled": true, + "core": false, + "latest_version": "3.2.0", + "installed_version": "3.2.0", + "status": "error", + "pkg_type": "prebuilt", + "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.", + "url": "https://github.com/jupyter-widgets/ipywidgets", + "enabled": true, + "core": false, + "latest_version": "3.1.0", + "installed_version": "3.1.0", + "status": "error", + "pkg_type": "prebuilt", + "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 0000000..c013435 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 0000000..50e703e --- /dev/null +++ b/galata/test/documentation/debugger.test.ts @@ -0,0 +1,271 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; +import { positionMouse, 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); + + expect( + await page.screenshot({ + clip: { x: 1050, y: 62, width: 190, 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: 800, width: 190, 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); + + 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); + + // Inject mouse pointer + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [positionMouse({ x: 446, y: 80 })] + ); + + expect( + await page.screenshot({ clip: { y: 62, x: 400, width: 190, height: 80 } }) + ).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('Debugger sidebar', async ({ page, tmpPath }) => { + await page.goto(`tree/${tmpPath}`); + + await createNotebook(page); + + await page.click('[data-id="jp-debugger-sidebar"]'); + await setSidebarWidth(page, 251, 'right'); + + // Inject mouse pointer + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [positionMouse({ x: 1240, y: 115 })] + ); + + 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 + await page.debugger.waitForCallStack(); + + expect( + await page.screenshot({ + clip: { y: 58, x: 998, width: 280, height: 138 } + }) + ).toMatchSnapshot('debugger_variables.png'); + + await page.click('button[title^=Continue]'); + }); + + 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.*\/2114632017.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 0000000..fcd9d17 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 0000000..207c694 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 0000000..8cc974e 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 0000000..2558bdf 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 0000000..504e280 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 0000000..3c35f57 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-variables-documentation-linux.png b/galata/test/documentation/debugger.test.ts-snapshots/debugger-variables-documentation-linux.png new file mode 100644 index 0000000..d2998c6 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 0000000..b41e814 --- /dev/null +++ b/galata/test/documentation/export_notebook.test.ts @@ -0,0 +1,62 @@ +// 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('ul[role="menu"] >> text=Save and Export Notebook As'); + + // Wait for Latex renderer + 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.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('[title="Property Inspector"]'); + await page.pause(); + await page.selectOption( + '.jp-PropertyInspector >> text=Slide Type >> select', + { label: 'Slide' } + ); + // Wait for Latex renderer + await page.waitForSelector('text=(đœŽĪƒ, đ›Ŋβ, đœŒĪ)'); + + 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 0000000..7301b19 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 0000000..4141531 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 0000000..e31927e --- /dev/null +++ b/galata/test/documentation/extension_manager.test.ts @@ -0,0 +1,204 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + expect, + galata, + IJupyterLabPageFixture, + test +} from '@jupyterlab/galata'; +import { setSidebarWidth, stubDrawioExtensionsSearch } from './utils'; +import { default as extensionsList } from './data/extensions.json'; +import { default as allExtensionsList } from './data/extensions-search-all.json'; + +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) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(extensionsList) + }); + default: + return route.continue(); + } + }); + + await page.route( + 'https://registry.npmjs.org/-/v1/search*text=+keywords%3A%22jupyterlab-extension%22*', + async (route, request) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(allExtensionsList) + }); + default: + return route.continue(); + } + } + ); + }); + + test('Sidebar', async ({ page }) => { + await page.goto(); + + await page.pause(); + 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 stubDrawioExtensionsSearch(page); + + await page.goto(); + + await openExtensionSidebar(page); + + await page.fill( + '.jp-extensionmanager-view >> [placeholder="SEARCH"]', + 'drawio' + ); + + await page.keyboard.press('Tab'); + + // 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('With allowed and blocked list', async ({ page }) => { + await page.route( + /.*\/api\/listings\/.*\/listings\.json.*/, + (route, request) => { + if (request.method() === 'GET') { + return route.fulfill({ + status: 200, + body: `{ + "blocked_extensions_uris": ["http://banana.json/"], + "allowed_extensions_uris": ["http://orange.json/"], + "blocked_extensions": [{"name":"banana","type":"jupyterlab"}], + "allowed_extensions": [{"name":"orange","type":"jupyterlab"}] + }` + }); + } else { + return route.continue(); + } + } + ); + await page.goto(); + + await page.click('[title="Extension Manager"]'); + + expect( + await page.screenshot({ clip: { y: 31, x: 0, width: 283, height: 160 } }) + ).toMatchSnapshot('extensions_simultaneous_block_allow.png'); + }); + + test('Blocked installed extension', async ({ page }) => { + await page.route( + /.*\/api\/listings\/.*\/listings\.json.*/, + (route, request) => { + if (request.method() === 'GET') { + return route.fulfill({ + status: 200, + body: `{ + "blocked_extensions_uris": ["http://banana.json/"], + "allowed_extensions_uris": [], + "blocked_extensions": [{"name":"@jupyter-widgets/jupyterlab-manager","type":"jupyterlab"}], + "allowed_extensions": [] + }` + }); + } else { + return route.continue(); + } + } + ); + await page.goto(); + + await openExtensionSidebar(page); + + expect( + await page.screenshot({ + clip: { y: 110, x: 33, width: 250, height: 280 } + }) + ).toMatchSnapshot('extensions_blocked_list.png'); + }); + + test('Allowed installed extension', async ({ page }) => { + await page.route( + /.*\/api\/listings\/.*\/listings\.json.*/, + (route, request) => { + if (request.method() === 'GET') { + return route.fulfill({ + status: 200, + body: `{ + "blocked_extensions_uris": [], + "allowed_extensions_uris": ["http://banana.json/"], + "blocked_extensions": [], + "allowed_extensions": [{"name":"@jupyter-widgets/jupyterlab-manager","type":"jupyterlab"}] + }` + }); + } else { + return route.continue(); + } + } + ); + await page.goto(); + + await openExtensionSidebar(page); + + expect( + await page.screenshot({ + clip: { y: 110, x: 33, width: 250, height: 280 } + }) + ).toMatchSnapshot('extensions_allowed_list.png'); + }); +}); + +async function openExtensionSidebar(page: IJupyterLabPageFixture) { + await page.click('[title="Extension Manager"]'); + + await page.click('button:has-text("Enable")'); + await page.waitForSelector('button:has-text("Disable")'); + await page.click( + '.jp-extensionmanager-view >> .jp-stack-panel-header >> button' + ); + + 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 0000000..53b2253 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 0000000..298c9f6 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 0000000..d173aa4 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 0000000..e553079 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 0000000..c4c9ffd 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 0000000..8de5dc7 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/extension_manager.test.ts-snapshots/extensions-simultaneous-block-allow-documentation-linux.png b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-simultaneous-block-allow-documentation-linux.png new file mode 100644 index 0000000..2335675 Binary files /dev/null and b/galata/test/documentation/extension_manager.test.ts-snapshots/extensions-simultaneous-block-allow-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 0000000..4273490 --- /dev/null +++ b/galata/test/documentation/general.test.ts @@ -0,0 +1,581 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, galata, test } from '@jupyterlab/galata'; +import { generateArrow, positionMouse, 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('ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Terminal'); + + await page.click('text=File'); + await page.click('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'); + + 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 setSidebarWidth(page); + + await page.notebook.createNew(); + await page.click('[title="Property Inspector"]'); + + expect( + await page.screenshot({ + clip: { y: 32, x: 997, width: 283, height: 400 } + }) + ).toMatchSnapshot('interface_right.png'); + }); + + test('Open tabs', async ({ page }) => { + await openOverview(page); + + await page.click('[title="Running Terminals and Kernels"]'); + + 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); + await page.click('ul[role="menu"] >> text=New'); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [positionMouse({ x: 35, y: 35 })] + ); + + 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'); + const itemBBox = await itemHandle.boundingBox(); + + // Inject mouse + await page.evaluate( + ([mouse]) => { + document.body.insertAdjacentHTML('beforeend', mouse); + }, + [positionMouse({ x: 260, y: itemBBox.y + itemBBox.height * 0.5 })] + ); + + 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('ul[role="menu"] >> text=New'); + await page.hover('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('ul[role="menu"] >> text=Text Editor Key Map'); + + expect( + await page.screenshot({ clip: { y: 0, x: 260, width: 600, height: 450 } }) + ).toMatchSnapshot('file_editor_settings.png'); + }); + + test('Notebook', 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'); + + 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(); + + // Relax threshold as displayed map may change a bit (in particular text positioning) + expect(await page.screenshot()).toMatchSnapshot('notebook_ui.png', { + threshold: 0.3 + }); + }); + + 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('ul[role="menu"] >> text=New'); + await page.click('#jp-mainmenu-file-new >> text=Terminal'); + + await page.waitForSelector('.jp-Terminal'); + + 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('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"]'); + + 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('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('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 + }); + }); + + test('VDOM', 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\nfrom vdom.helpers import h1, p, img, div, b\n\ndisplay(\ndiv(\nh1('Our Incredibly Declarative Example'),\np('Can you believe we wrote this ', b('in Python'), '?'),\nimg(src='https://turnoff.us/image/en/death-and-the-programmer.png', style={'height': '268px'}),\np('What will ', b('you'), ' create next?')))" + ); + + await page.notebook.run(); + + expect(await page.screenshot()).toMatchSnapshot( + 'file_formats_nteract_vdom.png' + ); + }); +}); + +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 0000000..ece0491 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 0000000..c11b95b 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 0000000..90263cd 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 0000000..dc84ebf 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 0000000..ac75acc 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-nteract-vdom-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/file-formats-nteract-vdom-documentation-linux.png new file mode 100644 index 0000000..5dc19ba Binary files /dev/null and b/galata/test/documentation/general.test.ts-snapshots/file-formats-nteract-vdom-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 0000000..a50095f 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 0000000..bd52f72 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 0000000..f5e71d3 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 0000000..3d19d22 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 0000000..e8ab529 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 0000000..c6ede43 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 0000000..0d89c9d 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-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/interface-right-documentation-linux.png new file mode 100644 index 0000000..c03b3bd 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 0000000..5535eb8 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 0000000..1339554 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 0000000..1227648 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-ui-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/notebook-ui-documentation-linux.png new file mode 100644 index 0000000..1c3c13e 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 0000000..94db87e 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/terminal-layout-documentation-linux.png b/galata/test/documentation/general.test.ts-snapshots/terminal-layout-documentation-linux.png new file mode 100644 index 0000000..0047e74 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 0000000..5d57cad --- /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('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('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('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 0000000..0806691 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 0000000..0024aa3 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 0000000..b87891f 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/screenshots/debugger-breakpoints.png b/galata/test/documentation/screenshots/debugger-breakpoints.png new file mode 100644 index 0000000..8740130 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 0000000..7512287 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 0000000..b8169e5 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 0000000..d478082 --- /dev/null +++ b/galata/test/documentation/utils.ts @@ -0,0 +1,107 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { Page } from '@playwright/test'; +import { default as extensionsSearchStub } from './data/extensions-search-drawio.json'; +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 { + return ` + +`; +} + +/** + * 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 stubDrawioExtensionsSearch(page: Page): Promise { + await page.route( + 'https://registry.npmjs.org/-/v1/search*text=drawio*', + async (route, request) => { + switch (request.method()) { + case 'GET': + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(extensionsSearchStub) + }); + default: + return route.continue(); + } + } + ); + + // 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 86b15eb..2f4b46e 100644 --- a/galata/test/galata/benchmarkReporter.spec.ts +++ b/galata/test/galata/benchmarkReporter.spec.ts @@ -1,8 +1,7 @@ // 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 { expect, test } from '@jupyterlab/galata'; import { TestResult } from '@playwright/test/reporter'; import BenchmarkReporter, { benchmark, @@ -41,6 +40,7 @@ function mockTestResult( }[] ): TestResult { return { + errors: [], retry: 0, workerIndex: 0, startTime: new Date(), @@ -58,7 +58,7 @@ function createReporter(options?: { comparison?: 'snapshot' | 'project'; vegaLiteConfigFactory?: ( allData: Array, - comparison: 'snapshot' | 'project' + comparison?: 'snapshot' | 'project' ) => JSONObject; textReportFactory?: ( allData: Array @@ -95,9 +95,9 @@ test.describe('BenchmarkReporter', () => { const mdData = fs.readFileSync(outputMd, 'utf-8'); expect(mdData).toContain('## Benchmark report'); - const outputPng = path.resolve('.', `benchmark-results`, 'test.png'); - const pngData = fs.readFileSync(outputPng); - expect(pngData).toMatchSnapshot('test.png'); + const outputFigure = path.resolve('.', `benchmark-results`, 'test.svg'); + const figureData = fs.readFileSync(outputFigure); + expect(figureData).toMatchSnapshot('test.svg'); }); test('should generate report with user defined builders', async () => { @@ -112,8 +112,20 @@ test.describe('BenchmarkReporter', () => { const mdData = fs.readFileSync(outputMd, 'utf-8'); expect(mdData).toContain('## This is a custom table'); - const outputPng = path.resolve('.', 'benchmark-results', 'test.png'); - const pngData = fs.readFileSync(outputPng); - expect(pngData).toMatchSnapshot('customized_test.png'); + const outputFigure = path.resolve('.', 'benchmark-results', 'test.svg'); + const figureData = fs.readFileSync(outputFigure); + 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.png b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.png deleted file mode 100644 index aafc553..0000000 Binary files a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.png and /dev/null differ 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 new file mode 100644 index 0000000..eff5170 --- /dev/null +++ b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/customized-test-galata-linux.svg @@ -0,0 +1 @@ +Duration of common actions \ No newline at end of file diff --git a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.png b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.png deleted file mode 100644 index a0e5155..0000000 Binary files a/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.png and /dev/null differ 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 new file mode 100644 index 0000000..af670ab --- /dev/null +++ b/galata/test/galata/benchmarkReporter.spec.ts-snapshots/test-galata-linux.svg @@ -0,0 +1 @@ +browseractualexpectedreferencechromium18,204Time (ms)openlarge_code_notebookDuration of common actions \ No newline at end of file diff --git a/galata/test/galata/contents.spec.ts b/galata/test/galata/contents.spec.ts index a7994d8..1965ebf 100644 --- a/galata/test/galata/contents.spec.ts +++ b/galata/test/galata/contents.spec.ts @@ -4,8 +4,7 @@ import * as path from 'path'; -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, test } from '@jupyterlab/galata'; test.describe('Contents API Tests', () => { test('Upload directory to server', async ({ page, tmpPath }) => { diff --git a/galata/test/galata/fixture.spec.ts b/galata/test/galata/fixture.spec.ts index 470ba30..f3fd44c 100644 --- a/galata/test/galata/fixture.spec.ts +++ b/galata/test/galata/fixture.spec.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { expect } from '@playwright/test'; -import { JupyterLabPage, test } from '@jupyterlab/galata'; +import { expect, JupyterLabPage, test } from '@jupyterlab/galata'; test.describe('page', () => { test('should return a JupyterLabPage', ({ page }) => { @@ -17,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 ); }); }); diff --git a/galata/test/galata/jupyterlabpage.spec.ts b/galata/test/galata/jupyterlabpage.spec.ts index 75f24ff..b32e418 100644 --- a/galata/test/galata/jupyterlabpage.spec.ts +++ b/galata/test/galata/jupyterlabpage.spec.ts @@ -1,8 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { test } from '@jupyterlab/galata'; -import { expect, test as playwrightTest } from '@playwright/test'; +import { expect, test } from '@jupyterlab/galata'; +import { test as playwrightTest } from '@playwright/test'; test.describe('appPath', () => { const APP_PATH = '/retro'; @@ -47,8 +47,6 @@ 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'); }); diff --git a/galata/test/galata/notebook.spec.ts b/galata/test/galata/notebook.spec.ts index 921a6e3..c04d2c6 100644 --- a/galata/test/galata/notebook.spec.ts +++ b/galata/test/galata/notebook.spec.ts @@ -4,8 +4,7 @@ import * as path from 'path'; -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, test } from '@jupyterlab/galata'; test.describe('Notebook Tests', () => { test('Create New Notebook', async ({ page, tmpPath }) => { 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 0d8110d..b5153a0 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 220a6c9..10a09b2 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 6e943ed..a7b857f 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 081ba8a..c4f11d1 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 2b27907..b9ca749 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/simple_test.ipynb b/galata/test/galata/notebooks/simple_test.ipynb index 809a1be..e1ab32b 100644 --- a/galata/test/galata/notebooks/simple_test.ipynb +++ b/galata/test/galata/notebooks/simple_test.ipynb @@ -486,4 +486,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/galata/test/galata/test.spec.ts b/galata/test/galata/test.spec.ts index cfe5288..17bc4b8 100644 --- a/galata/test/galata/test.spec.ts +++ b/galata/test/galata/test.spec.ts @@ -2,8 +2,7 @@ // Copyright (c) Bloomberg Finance LP. // Distributed under the terms of the Modified BSD License. -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, test } from '@jupyterlab/galata'; test('should display the launcher', async ({ page }) => { expect(await page.waitForSelector(page.launcherSelector)).toBeTruthy(); diff --git a/galata/test/jupyterlab/collapsible-headings.test.ts b/galata/test/jupyterlab/collapsible-headings.test.ts new file mode 100644 index 0000000..53816d4 --- /dev/null +++ b/galata/test/jupyterlab/collapsible-headings.test.ts @@ -0,0 +1,273 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, 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: { + '@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 0000000..7a5cec5 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 0000000..233dea0 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 0000000..d0e0962 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 0000000..664aee7 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 0000000..2bd6760 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 0000000..8d7de15 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 0000000..f07b519 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 0000000..3edfe81 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 0000000..bd0ad3f 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 0000000..52c480f 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 0000000..fe3aa63 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 0000000..470bde0 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 0000000..e72716f 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 0000000..ecffa43 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 0000000..2f6eb39 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 0000000..3edfe81 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 0000000..c21eb11 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 0000000..68693e7 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 0000000..fe3aa63 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 0000000..470bde0 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 0000000..4265f2c 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 6812c33..bdd8ca8 100644 --- a/galata/test/jupyterlab/completer.test.ts +++ b/galata/test/jupyterlab/completer.test.ts @@ -1,8 +1,7 @@ // 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 { expect, test } from '@jupyterlab/galata'; const fileName = 'notebook.ipynb'; const COMPLETER_SELECTOR = '.jp-Completer'; @@ -26,10 +25,14 @@ 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'); - - const completer = page.locator(COMPLETER_SELECTOR); + 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'; // TODO: on first trigger types are not properly displayed, reference image will need updating expect(await completer.screenshot()).toMatchSnapshot(imageName); @@ -50,10 +53,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); @@ -66,7 +74,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.'); 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 fa38430..808d06e 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 e23198d..a5811ac 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 37f0f8c..17ca32f 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 f43ac98..b7c303c 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/contextmenu.test.ts b/galata/test/jupyterlab/contextmenu.test.ts index a0bd97a..9b2333b 100644 --- a/galata/test/jupyterlab/contextmenu.test.ts +++ b/galata/test/jupyterlab/contextmenu.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { galata, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, galata, test } from '@jupyterlab/galata'; import * as path from 'path'; @@ -16,8 +15,8 @@ test.use({ }); test.describe('Application Context Menu', () => { - test.beforeAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.beforeAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, request); // Create some dummy content await contents.uploadFile( @@ -43,8 +42,8 @@ test.describe('Application Context Menu', () => { await page.filebrowser.openHomeDirectory(); }); - test.afterAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.afterAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, request); await contents.deleteDirectory(tmpPath); }); @@ -79,6 +78,27 @@ test.describe('Application Context Menu', () => { expect(await menu.screenshot()).toMatchSnapshot(imageName); }); + test('Open file browser context menu on notebook with kernel', async ({ + page, + tmpPath + }) => { + await page.notebook.openByPath(`${tmpPath}/${testNotebook}`); + // Wait for kernel to be idle + expect( + await page.waitForSelector(`#jp-main-statusbar >> text=Idle`) + ).toBeTruthy(); + + await page.click(`.jp-DirListing-item span:has-text("${testNotebook}")`, { + button: 'right' + }); + // Context menu should be available + expect(await page.menu.isAnyOpen()).toBe(true); + + const imageName = 'running-notebook.png'; + const menu = await page.menu.getOpenMenu(); + expect(await menu.screenshot()).toMatchSnapshot(imageName); + }); + test('Open file browser context submenu open with', async ({ page }) => { await page.sidebar.openTab(filebrowserId); expect(await page.sidebar.isTabOpen(filebrowserId)).toBeTruthy(); 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 bfa2b5d..03b7c46 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 15d5bda..964589a 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 8849a3b..ce26b15 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 bcb3ddc..1d42fde 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 c290e9c..6c37b5d 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 54c3e2d..0dc2672 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 new file mode 100644 index 0000000..ea5cd12 Binary files /dev/null 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 341f991..50e37e7 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 da06f33..625eea7 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 666301d..8d72a5b 100644 --- a/galata/test/jupyterlab/debugger.test.ts +++ b/galata/test/jupyterlab/debugger.test.ts @@ -1,10 +1,23 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; +import * as path from 'path'; -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +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( @@ -16,4 +29,88 @@ 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('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' + ); + }); }); 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 0000000..1ae1456 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 0000000..fcc84d8 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 0000000..9ae1eb1 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 0000000..fcc84d8 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 b/galata/test/jupyterlab/general.test.ts index 43d334a..2961ca8 100644 --- a/galata/test/jupyterlab/general.test.ts +++ b/galata/test/jupyterlab/general.test.ts @@ -1,8 +1,7 @@ // 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 { expect, test } from '@jupyterlab/galata'; test.describe('General Tests', () => { test('Launch Screen', async ({ page }) => { 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 c0a0f23..cf40a9a 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 5d4505e..77f93be 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 8f4e6ef..388d20c 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/menus.test.ts b/galata/test/jupyterlab/menus.test.ts index 6d4b692..4e5c576 100644 --- a/galata/test/jupyterlab/menus.test.ts +++ b/galata/test/jupyterlab/menus.test.ts @@ -1,14 +1,15 @@ // 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 { expect, test } from '@jupyterlab/galata'; +import type { ISettingRegistry } from '@jupyterlab/settingregistry'; const menuPaths = [ 'File', 'File>New', 'Edit', 'View', + 'View>Appearance', 'Run', 'Kernel', 'Tabs', @@ -22,9 +23,9 @@ const menuPaths = [ '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(); @@ -42,8 +43,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(); @@ -67,3 +67,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.galataip.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.galataip.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 f459111..94d65e4 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 43b3e1e..6046146 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 5053ba8..fa520d5 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 0555f5f..fd15a49 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 91ce128..130c86c 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 4e0ea3d..4a7a958 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 39527b1..a3158fb 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 5869672..0a4160b 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 6e9e7b3..308ca7d 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 bec6a5d..dbed241 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 b164057..1d59825 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-key-map-jupyterlab-linux.png b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-key-map-jupyterlab-linux.png index 6fef53a..b802496 100644 Binary files a/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-key-map-jupyterlab-linux.png and b/galata/test/jupyterlab/menus.test.ts-snapshots/opened-menu-settings-text-editor-key-map-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 b87541d..4cb3ebe 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 5a83a90..889f23b 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 6ff6595..6275d04 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 0000000..cfbbde2 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 96aa937..2bd1b52 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 19e1c41..34f813d 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 b7adebf..4c9bf66 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 2fc0abc..9c4b8fb 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 cbf9ad0..bde7085 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 1a5480b..36e470b 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 0d405f7..4981056 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/notebook-create.test.ts b/galata/test/jupyterlab/notebook-create.test.ts index 5324144..12e4eb2 100644 --- a/galata/test/jupyterlab/notebook-create.test.ts +++ b/galata/test/jupyterlab/notebook-create.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IJupyterLabPageFixture, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; const fileName = 'notebook.ipynb'; 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 dbeed4c..e352b4a 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 ac87753..ac2d979 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 45a3723..bb7c3b7 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 e4c9745..85137d5 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 13cdfcd..0c04e65 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 433d405..0f13c45 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 807eb99..edbf06d 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 1b8a192..9b391f1 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 ac6ad1c..c8055d9 100644 --- a/galata/test/jupyterlab/notebook-edit.test.ts +++ b/galata/test/jupyterlab/notebook-edit.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IJupyterLabPageFixture, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; const fileName = 'notebook.ipynb'; 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 07e2092..7af6eb7 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 64a718c..b7fff93 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 e5c3a01..459bde3 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 4ce3f7a..f6c254f 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 17e0e74..94da3ac 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 9a1c6ed..6aff3c0 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 64a718c..b7fff93 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 e9a1f05..9cd7a7e 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 ad8e31f..ddd6509 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 17e0e74..94da3ac 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 c9e112a..32b8f22 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 801b403..b406db3 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 5b5d329..fa66ac8 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 b/galata/test/jupyterlab/notebook-markdown.test.ts index 77bc2e2..ffe3f75 100644 --- a/galata/test/jupyterlab/notebook-markdown.test.ts +++ b/galata/test/jupyterlab/notebook-markdown.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IJupyterLabPageFixture, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; import * as path from 'path'; const fileName = 'markdown_notebook.ipynb'; 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 2f9549e..338a8dc 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 739ec78..ddf6505 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 55f3d6f..02c7f5d 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 new file mode 100644 index 0000000..7790f14 --- /dev/null +++ b/galata/test/jupyterlab/notebook-max-outputs.test.ts @@ -0,0 +1,87 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +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: MAX_OUTPUTS + } + } +}); + +test('Limit cell outputs', async ({ page }) => { + await page.notebook.createNew(); + + 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**')) +`); + + await page.notebook.run(); + + await expect(page.locator('.jp-RenderedMarkdown')).toHaveCount(MAX_OUTPUTS); + await expect(page.locator('.jp-TrimmedOutputs')).toHaveText( + 'Show more outputs' + ); +}); + +test("Don't limit cell outputs if input is requested", async ({ page }) => { + await page.notebook.createNew(); + + 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**')) + +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( + MAX_OUTPUTS + ); + + await page.keyboard.press('Enter'); +}); + +test('Display input value', async ({ page }) => { + await page.notebook.createNew(); + + 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**')) + +input('Your age:') + +for i in range(10): + display(Markdown('_Markdown_ **text**')) +`); + + await page.menu.clickMenuItem('Run>Run All Cells'); + await page.waitForSelector('.jp-Stdin >> text=Your age:'); + + await page.keyboard.type('42'); + await page.keyboard.press('Enter'); + + 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 0000000..2581899 --- /dev/null +++ b/galata/test/jupyterlab/notebook-mobile.test.ts @@ -0,0 +1,24 @@ +// 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'); + 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 0000000..ba2dcf6 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 0000000..625f926 --- /dev/null +++ b/galata/test/jupyterlab/notebook-replace.test.ts @@ -0,0 +1,94 @@ +// 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('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'); + }); +}); 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 0000000..2473321 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 0000000..e833a87 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 0000000..3665338 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 new file mode 100644 index 0000000..e04acc8 --- /dev/null +++ b/galata/test/jupyterlab/notebook-run-vega.test.ts @@ -0,0 +1,63 @@ +// 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 = 'vega_notebook.ipynb'; + +test.use({ tmpPath: 'notebook-run-vega-test' }); + +test.describe.serial('Notebook Run Vega', () => { + test.beforeAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, 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}`); + await page.notebook.activate(fileName); + + const imageName = 'run-cells-vega.png'; + + await page.notebook.run(); + await page.waitForSelector('.vega-embed'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + }); + + test('Run notebook with Vega cell in dark theme', async ({ + page, + tmpPath + }) => { + await page.notebook.openByPath(`${tmpPath}/${fileName}`); + await page.notebook.activate(fileName); + await page.theme.setDarkTheme(); + + const imageName = 'run-cells-dark-vega.png'; + + await page.notebook.run(); + await page.waitForSelector('.vega-embed'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); + }); +}); 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 new file mode 100644 index 0000000..ed5f001 Binary files /dev/null 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 new file mode 100644 index 0000000..872be28 Binary files /dev/null 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 8282c15..52a16da 100644 --- a/galata/test/jupyterlab/notebook-run.test.ts +++ b/galata/test/jupyterlab/notebook-run.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { galata, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, galata, test } from '@jupyterlab/galata'; import * as path from 'path'; const fileName = 'simple_notebook.ipynb'; @@ -10,8 +9,8 @@ const fileName = 'simple_notebook.ipynb'; test.use({ tmpPath: 'notebook-run-test' }); test.describe.serial('Notebook Run', () => { - test.beforeAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.beforeAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${fileName}`), `${tmpPath}/${fileName}` @@ -26,8 +25,8 @@ test.describe.serial('Notebook Run', () => { await page.filebrowser.openDirectory(tmpPath); }); - test.afterAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.afterAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, request); await contents.deleteDirectory(tmpPath); }); 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 9aa4731..0fc15e8 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-search.test.ts b/galata/test/jupyterlab/notebook-search.test.ts new file mode 100644 index 0000000..29f1b75 --- /dev/null +++ b/galata/test/jupyterlab/notebook-search.test.ts @@ -0,0 +1,236 @@ +// 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', () => { + 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('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'); + + 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 selected cells', 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 Selected Cell(s)'); + + await page.waitForSelector('text=1/4'); + + const nbPanel = await page.notebook.getNotebookInPanel(); + + expect(await nbPanel.screenshot()).toMatchSnapshot( + 'search-in-selected-cells.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'); + + const cell = await page.notebook.getCell(5); + await cell.click(); + await page.keyboard.press('Escape'); + await cell.scrollIntoViewIfNeeded(); + + // Click previous button + await page.click('button[title="Previous Match"]'); + await page.waitForSelector('text=19/21'); + + const hit = await page.notebook.getCell(2); + expect(await hit.screenshot()).toMatchSnapshot( + 'highlight-previous-element.png' + ); + }); + + 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'); + + 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=-/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 0000000..5f169f6 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 0000000..05f6f3f 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 0000000..254bd1b 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 0000000..4e832d2 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/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 0000000..8144a4a 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-jupyterlab-linux.png b/galata/test/jupyterlab/notebook-search.test.ts-snapshots/search-jupyterlab-linux.png new file mode 100644 index 0000000..bbddd4e 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 0000000..ba7470c 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 0000000..608bddb 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 0000000..c91a33c 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 0000000..7a2e04c 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 0000000..8e1d3bf 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 7a3cfce..dad9c7a 100644 --- a/galata/test/jupyterlab/notebook-toolbar.test.ts +++ b/galata/test/jupyterlab/notebook-toolbar.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { IJupyterLabPageFixture, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, IJupyterLabPageFixture, test } from '@jupyterlab/galata'; const fileName = 'notebook.ipynb'; @@ -13,7 +12,6 @@ async function populateNotebook(page: IJupyterLabPageFixture) { '## This is **bold** and *italic* [link to jupyter.org!](http://jupyter.org)' ); await page.notebook.addCell('code', '2 ** 3'); - // await page.notebook.runCell(2, true); } test.describe('Notebook Toolbar', () => { @@ -100,3 +98,44 @@ test.describe('Notebook Toolbar', () => { expect(await nbPanel.screenshot()).toMatchSnapshot(imageName); }); }); + +test('Toolbar items act on owner widget', async ({ page }) => { + // Given two side-by-side notebooks and the second being active + const file1 = 'notebook1.ipynb'; + await page.notebook.createNew(file1); + const panel1 = await page.activity.getPanel(file1); + const tab1 = await page.activity.getTab(file1); + + // FIXME Calling a second time `page.notebook.createNew` is not robust + await page.menu.clickMenuItem('File>New>Notebook'); + try { + await page.waitForSelector('.jp-Dialog', { timeout: 5000 }); + await page.click('.jp-Dialog .jp-mod-accept'); + } catch (reason) { + // no-op + } + + const tab2 = await page.activity.getTab(); + + const tab2BBox = await tab2.boundingBox(); + await page.mouse.move( + tab2BBox.x + 0.5 * tab2BBox.width, + tab2BBox.y + 0.5 * tab2BBox.height + ); + await page.mouse.down(); + await page.mouse.move(900, tab2BBox.y + tab2BBox.height + 200); + await page.mouse.up(); + + const classlist = await tab1.getAttribute('class'); + expect(classlist.split(' ')).not.toContain('jp-mod-current'); + + // When clicking on toolbar item of the first file + 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'); + expect(classlistEnd.split(' ')).toContain('jp-mod-current'); + expect(await page.notebook.getCellCount()).toEqual(2); +}); 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 fabfced..b3e3680 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 65384f3..e899938 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 88039ca..2b5137f 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 18fc2cc..9192973 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 eb26fd6..c198c0c 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 0000000..dfa20e7 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 063b6e2..834f1a6 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 e1b01e4..a77e5bb 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/notebooks/code_notebook.ipynb b/galata/test/jupyterlab/notebooks/code_notebook.ipynb new file mode 100644 index 0000000..df097ac --- /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 0000000..79ee581 --- /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/search.ipynb b/galata/test/jupyterlab/notebooks/search.ipynb new file mode 100644 index 0000000..284dc99 --- /dev/null +++ b/galata/test/jupyterlab/notebooks/search.ipynb @@ -0,0 +1,139 @@ +{ + "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", + " {\"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", + " {\"text/markdown\": \"# Plain text with\\nmultiple with hits.\"},\n", + " {\"text/html\": \"

    Plain text with

    multiple with hits.

    \"}\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/toc_notebook.ipynb b/galata/test/jupyterlab/notebooks/toc_notebook.ipynb index ec6b34e..dbfca41 100644 --- a/galata/test/jupyterlab/notebooks/toc_notebook.ipynb +++ b/galata/test/jupyterlab/notebooks/toc_notebook.ipynb @@ -18,35 +18,49 @@ "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", + "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 +69,14 @@ "metadata": {}, "outputs": [], "source": [ - "from IPython.display import Image" + "sleep(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Image" + "## Multiple output types" ] }, { @@ -71,7 +85,7 @@ "metadata": {}, "outputs": [], "source": [ - "Image(\"WidgetArch.png\", width=70, height=100)" + "from IPython.display import display" ] }, { @@ -80,7 +94,19 @@ "metadata": {}, "outputs": [], "source": [ - "2 + 2" + "outputs =[ \n", + " {\"text/markdown\": \"# Markdown title\\nmultiple with hits.\"},\n", + " {\"text/html\": \"

    HTML title

    multiple with hits.

    \"}\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display(*outputs, raw=True)" ] }, { @@ -110,12 +136,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.4" + "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/vega_notebook.ipynb b/galata/test/jupyterlab/notebooks/vega_notebook.ipynb new file mode 100644 index 0000000..9a7f56b --- /dev/null +++ b/galata/test/jupyterlab/notebooks/vega_notebook.ipynb @@ -0,0 +1,56 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "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)" + ] + } + ], + "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.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/galata/test/jupyterlab/search.test.ts b/galata/test/jupyterlab/search.test.ts new file mode 100644 index 0000000..e00861e --- /dev/null +++ b/galata/test/jupyterlab/search.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'; + +const DEFAULT_NAME = 'untitled.txt'; + +const TEST_FILE_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 +ut elit.`; + +test('Search with a text', async ({ page }) => { + const searchText = 'ipsum'; + await page.menu.clickMenuItem('File>New>Text File'); + + await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); + + await page.type('.cm-content', TEST_FILE_CONTENT); + + await page.evaluate(async searchText => { + await window.jupyterapp.commands.execute('documentsearch:start', { + searchText + }); + }, searchText); + + expect( + await page.locator('input.jp-DocumentSearch-input').inputValue() + ).toEqual(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.type('.cm-content', TEST_FILE_CONTENT); + + await page.evaluate( + async ([searchText, replaceText]) => { + await window.jupyterapp.commands.execute( + 'documentsearch:startWithReplace', + { + searchText, + replaceText + } + ); + }, + [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); +}); diff --git a/galata/test/jupyterlab/settings.test.ts b/galata/test/jupyterlab/settings.test.ts new file mode 100644 index 0000000..fcf809a --- /dev/null +++ b/galata/test/jupyterlab/settings.test.ts @@ -0,0 +1,21 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { test } from '@jupyterlab/galata'; +import { expect } from '@playwright/test'; + +test('Open the settings editor with a specific search query', async ({ + page +}) => { + await page.evaluate(async () => { + await window.jupyterapp.commands.execute('settingeditor:open', { + query: 'Command Palette' + }); + }); + + expect( + await page.locator('.jp-PluginList .jp-FilterBox input').inputValue() + ).toEqual('Command Palette'); + + await expect(page.locator('.jp-SettingsForm')).toHaveCount(1); +}); diff --git a/galata/test/jupyterlab/shortcuts.test.ts b/galata/test/jupyterlab/shortcuts.test.ts new file mode 100644 index 0000000..f064e14 --- /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 324420f..d1aa7a5 100644 --- a/galata/test/jupyterlab/sidebars.test.ts +++ b/galata/test/jupyterlab/sidebars.test.ts @@ -1,8 +1,7 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { galata, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, galata, test } from '@jupyterlab/galata'; const sidebarIds: galata.SidebarTabId[] = [ 'filebrowser', 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 57cf407..934a74b 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/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 b9041ab..1073a42 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 2724459..5e1277b 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 cbf9ad0..d5e1350 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 f80fe05..49055f9 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 0d405f7..2931e28 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/terminal.test.ts b/galata/test/jupyterlab/terminal.test.ts index cf6b51e..9369117 100644 --- a/galata/test/jupyterlab/terminal.test.ts +++ b/galata/test/jupyterlab/terminal.test.ts @@ -1,5 +1,9 @@ -import { test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +/* + * 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'; const TERMINAL_THEME_ATTRIBUTE = 'data-term-theme'; @@ -84,3 +88,18 @@ test.describe('Terminal', () => { }); }); }); + +test('Terminal should open in Launcher cwd', async ({ page, tmpPath }) => { + await page.waitForSelector(`.jp-Launcher-cwd > h3:has-text("${tmpPath}")`); + + await page.locator('[role="main"] >> p:has-text("Terminal")').click(); + + const terminal = page.locator(TERMINAL_SELECTOR); + await terminal.waitFor(); + + await page.waitForTimeout(1000); + await page.keyboard.type('basename $PWD'); + await page.keyboard.press('Enter'); + await page.waitForTimeout(1000); + expect(await terminal.screenshot()).toMatchSnapshot('launcher-term.png'); +}); diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-dark-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-dark-jupyterlab-linux.png index ee77376..643f8a4 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-dark-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-dark-jupyterlab-linux.png differ 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 6af450a..ee868f8 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/dark-term-light-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-light-jupyterlab-linux.png index a0b6744..dcafe31 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-light-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/dark-term-light-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 new file mode 100644 index 0000000..0ed5aff Binary files /dev/null and b/galata/test/jupyterlab/terminal.test.ts-snapshots/launcher-term-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-dark-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-dark-jupyterlab-linux.png index 767c53a..3694af9 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-dark-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-dark-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-inherit-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-inherit-jupyterlab-linux.png index f991fe8..1fca753 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-inherit-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-inherit-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-light-jupyterlab-linux.png b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-light-jupyterlab-linux.png index 48fa1b9..f6ad02f 100644 Binary files a/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-light-jupyterlab-linux.png and b/galata/test/jupyterlab/terminal.test.ts-snapshots/light-term-light-jupyterlab-linux.png differ diff --git a/galata/test/jupyterlab/texteditor.test.ts b/galata/test/jupyterlab/texteditor.test.ts index d20d4f2..c348a1f 100644 --- a/galata/test/jupyterlab/texteditor.test.ts +++ b/galata/test/jupyterlab/texteditor.test.ts @@ -1,8 +1,7 @@ // 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 { expect, test } from '@jupyterlab/galata'; const DEFAULT_NAME = 'untitled.txt'; @@ -23,8 +22,9 @@ test.describe('Text Editor Tests', () => { await page.waitForSelector(`[role="main"] >> text=${DEFAULT_NAME}`); - 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'); // Add two rulers @@ -51,4 +51,34 @@ test.describe('Text Editor Tests', () => { expect(await tabHandle.screenshot()).toMatchSnapshot(imageName); }); + + 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.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 +ut elit.` + ); + + await page.evaluate(async () => { + await window.jupyterapp.commands.execute('codemirror:go-to-line', { + line: 2, + column: 8 + }); + }); + + await page.keyboard.type('#2:8#'); + + const tabHandle = await page.activity.getPanel(DEFAULT_NAME); + expect(await tabHandle.screenshot()).toMatchSnapshot(imageName); + }); }); 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 new file mode 100644 index 0000000..e26367f Binary files /dev/null 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-jupyterlab-linux.png b/galata/test/jupyterlab/texteditor.test.ts-snapshots/text-editor-jupyterlab-linux.png index 6d4eee2..3177537 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 a181989..3177537 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 231c26f..7ffd6a9 100644 --- a/galata/test/jupyterlab/toc-running.test.ts +++ b/galata/test/jupyterlab/toc-running.test.ts @@ -1,23 +1,24 @@ // 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 { 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"]' + ); }); test('should display running indicators', async ({ page }) => { @@ -40,9 +41,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); @@ -54,20 +57,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 executed = page.notebook.runCell(3); - - await expect( - tocPanel.waitForSelector('li:has-text("[*]: xxxxxxxxxx sleep(2)")') - ).toBeDefined(); - - 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 e96b35d..b174608 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 861f6b5..6a637b9 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.test.ts b/galata/test/jupyterlab/toc.test.ts index b127022..ea57bd7 100644 --- a/galata/test/jupyterlab/toc.test.ts +++ b/galata/test/jupyterlab/toc.test.ts @@ -1,234 +1,91 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { galata, test } from '@jupyterlab/galata'; -import { expect } from '@playwright/test'; +import { expect, galata, test } from '@jupyterlab/galata'; import * as path from 'path'; const fileName = 'toc_notebook.ipynb'; test.use({ tmpPath: 'test-toc' }); -test.describe.serial('Table of Contents', () => { - test.beforeAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); +test.describe('Table of Contents', () => { + test.beforeAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, 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, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.afterAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, 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') - ); - - 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 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(); - - 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 numberingButton = await tocPanel.$$( + 'button[data-command="toc:display-numbering"]' ); - 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(); + expect(numberingButton.length).toBe(1); - 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'); + await page + .locator('.jp-TableOfContents-tree >> text="2. Multiple output types"') + .click({ + button: 'right' + }); - const imageName = 'toggle-tag-2.png'; - await tags[1].click(); - - 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 tocPanel = await page.sidebar.getContentPanel( - await page.sidebar.getTabPosition('table-of-contents') - ); + const menu = await page.menu.getOpenMenu(); - await (await tocPanel.$('li > .toc-level-size-1')).click({ - button: 'right' - }); + await ( + await menu.$('text=Select and Run Cell(s) for this Heading') + ).click(); + await page.pause(); + 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/add-tags-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/add-tags-jupyterlab-linux.png deleted file mode 100644 index e0db18b..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/add-tags-jupyterlab-linux.png and /dev/null differ diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-context-menu-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-context-menu-jupyterlab-linux.png deleted file mode 100644 index d381854..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/notebook-context-menu-jupyterlab-linux.png and /dev/null differ 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 0000000..562c6eb 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/show-tags-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/show-tags-jupyterlab-linux.png deleted file mode 100644 index 571db39..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/show-tags-jupyterlab-linux.png and /dev/null 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 1ddb083..f1f1ab7 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-code-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-code-jupyterlab-linux.png deleted file mode 100644 index 252ab45..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-code-jupyterlab-linux.png and /dev/null differ diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-markdown-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-markdown-jupyterlab-linux.png deleted file mode 100644 index 11fe614..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-markdown-jupyterlab-linux.png and /dev/null 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 dd805f9..c195cc7 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/toc.test.ts-snapshots/toggle-tag-1-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-tag-1-jupyterlab-linux.png deleted file mode 100644 index 1fe9092..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-tag-1-jupyterlab-linux.png and /dev/null differ diff --git a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-tag-2-jupyterlab-linux.png b/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-tag-2-jupyterlab-linux.png deleted file mode 100644 index 4b540cf..0000000 Binary files a/galata/test/jupyterlab/toc.test.ts-snapshots/toggle-tag-2-jupyterlab-linux.png and /dev/null differ diff --git a/galata/test/jupyterlab/toolbars.test.ts b/galata/test/jupyterlab/toolbars.test.ts new file mode 100644 index 0000000..3905158 --- /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.galataip.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/workspace.test.ts b/galata/test/jupyterlab/workspace.test.ts index e0dd190..7125ad3 100644 --- a/galata/test/jupyterlab/workspace.test.ts +++ b/galata/test/jupyterlab/workspace.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { galata, test } from '@jupyterlab/galata'; -import { expect, Page } from '@playwright/test'; +import { expect, galata, test } from '@jupyterlab/galata'; +import { Page } from '@playwright/test'; import * as path from 'path'; const nbFile = 'simple_notebook.ipynb'; @@ -22,8 +22,8 @@ test.use({ }); test.describe('Workspace', () => { - test.beforeAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.beforeAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, request); await contents.uploadFile( path.resolve(__dirname, `./notebooks/${nbFile}`), `${tmpPath}/${nbFile}` @@ -34,8 +34,8 @@ test.describe('Workspace', () => { ); }); - test.afterAll(async ({ baseURL, tmpPath }) => { - const contents = galata.newContentsHelper(baseURL); + test.afterAll(async ({ baseURL, request, tmpPath }) => { + const contents = galata.newContentsHelper(baseURL, undefined, 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 9e98996..ea98d8d 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 9e98996..ea98d8d 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/update_snapshots.py b/galata/update_snapshots.py index aaa3ddf..1e446dc 100644 --- a/galata/update_snapshots.py +++ b/galata/update_snapshots.py @@ -1,41 +1,42 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import argparse import hashlib -from pathlib import Path import json import shutil +from pathlib import Path -import argparse -parser = argparse.ArgumentParser(description='Update Galata Snapshot images.') -parser.add_argument('report', help='Path to the galata-report directory') +parser = argparse.ArgumentParser(description="Update Galata Snapshot images.") +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() -filehashes = {sha1(p): p for p in Path('.').glob('**/*-snapshots/*-linux.png')} +filehashes = {sha1(p): p for p in Path(".").glob("**/*-snapshots/*-linux.png")} # For every json file in data directory except report.json -data_dir = Path(args.report).expanduser().resolve() / 'data' -for p in data_dir.glob('*.json'): - if p.name == 'report.json': +data_dir = Path(args.report).expanduser().resolve() / "data" +for p in data_dir.glob("*.json"): + if p.name == "report.json": continue with open(p, "rb") as f: z = json.load(f) - for t in z['tests']: - if t['outcome'] != 'unexpected': + for t in z["tests"]: + if t["outcome"] != "unexpected": continue - for r in t['results']: - for attachment in r['attachments']: - if attachment['name'] == 'expected': - expected = Path(attachment['path']).stem - elif attachment['name'] == 'actual': - actual = data_dir / Path(attachment['path']).name + for r in t["results"]: + for attachment in r["attachments"]: + if attachment["name"] == "expected": + expected = Path(attachment["path"]).stem + elif attachment["name"] == "actual": + actual = data_dir / Path(attachment["path"]).name if expected and attachment and expected in filehashes: shutil.copyfile(actual, filehashes[expected]) - print(f'{actual} -> {filehashes[expected]}') + print(f"{actual} -> {filehashes[expected]}") diff --git a/galata/webpack.config.js b/galata/webpack.config.js index d7109c9..1bfbf8c 100644 --- a/galata/webpack.config.js +++ b/galata/webpack.config.js @@ -4,6 +4,7 @@ const path = require('path'); const webpack = require('webpack'); +const miniSVGDataURI = require('mini-svg-data-uri'); module.exports = { entry: './src/inpage/index.ts', @@ -25,46 +26,44 @@ module.exports = { rules: [ { test: /\.ts$/, use: ['ts-loader'] }, { 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$/, enforce: 'pre', use: ['source-map-loader'] }, - { 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+)?$/, issuer: /\.css$/, - use: { - loader: 'svg-url-loader', - options: { encoding: 'none', limit: 10000 } + type: 'asset', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, issuer: /\.js$/, - use: { - loader: 'raw-loader' - } + type: 'asset/source' } ] }, diff --git a/jupyterhub.sqlite b/jupyterhub.sqlite deleted file mode 100644 index 7c75b26..0000000 Binary files a/jupyterhub.sqlite and /dev/null differ diff --git a/jupyterhub_cookie_secret b/jupyterhub_cookie_secret deleted file mode 100644 index 9d1eb79..0000000 --- a/jupyterhub_cookie_secret +++ /dev/null @@ -1 +0,0 @@ -3fc536cfed788a5667ecdde0783e62f651ddddaf348022faa2bc5c082604b704 diff --git a/jupyterlab/__init__.py b/jupyterlab/__init__.py index 1ff041f..a78323b 100644 --- a/jupyterlab/__init__.py +++ b/jupyterlab/__init__.py @@ -3,23 +3,15 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from ._version import __version__ -from .serverextension import load_jupyter_server_extension +from ._version import __version__ # noqa +from .serverextension import load_jupyter_server_extension # noqa def _jupyter_server_extension_paths(): - return [ - { - 'module': 'jupyterlab' - } - ] + return [{"module": "jupyterlab"}] def _jupyter_server_extension_points(): from .labapp import LabApp - return [ - { - 'module': 'jupyterlab', - 'app': LabApp - } - ] \ No newline at end of file + + return [{"module": "jupyterlab", "app": LabApp}] diff --git a/jupyterlab/__main__.py b/jupyterlab/__main__.py index 3f042c4..2f15f7c 100644 --- a/jupyterlab/__main__.py +++ b/jupyterlab/__main__.py @@ -1,4 +1,8 @@ -from jupyterlab.labapp import main +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + import sys +from jupyterlab.labapp import main + sys.exit(main()) diff --git a/jupyterlab/_version.py b/jupyterlab/_version.py index 7fb65b9..3d539a7 100644 --- a/jupyterlab/_version.py +++ b/jupyterlab/_version.py @@ -3,23 +3,20 @@ from collections import namedtuple -VersionInfo = namedtuple('VersionInfo', [ - 'major', - 'minor', - 'micro', - 'releaselevel', - 'serial' -]) +VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]) # DO NOT EDIT THIS DIRECTLY! It is managed by bumpversion -version_info = VersionInfo(3, 3, 2, 'final', 0) +version_info = VersionInfo(4, 0, 0, "alpha", 30) -_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''} +_specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""} -__version__ = '{}.{}.{}{}'.format( +__version__ = "{}.{}.{}{}".format( version_info.major, version_info.minor, version_info.micro, - ('' - if version_info.releaselevel == 'final' -else _specifier_[version_info.releaselevel] + str(version_info.serial))) + ( + "" + if version_info.releaselevel == "final" + else _specifier_[version_info.releaselevel] + str(version_info.serial) + ), +) diff --git a/jupyterlab/browser-test.js b/jupyterlab/browser-test.js index dce7677..b9cc660 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 inspect = require('util').inspect; const path = require('path'); diff --git a/jupyterlab/browser_check.py b/jupyterlab/browser_check.py index d3120c5..dcad834 100644 --- a/jupyterlab/browser_check.py +++ b/jupyterlab/browser_check.py @@ -1,5 +1,7 @@ - # -*- 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. @@ -27,21 +29,12 @@ here = osp.abspath(osp.dirname(__file__)) test_flags = dict(flags) -test_flags['core-mode'] = ( - {'BrowserApp': {'core_mode': True}}, - "Start the app in core mode." -) -test_flags['dev-mode'] = ( - {'BrowserApp': {'dev_mode': True}}, - "Start the app in dev mode." -) -test_flags['watch'] = ( - {'BrowserApp': {'watch': True}}, - "Start the app in watch mode." -) +test_flags["core-mode"] = ({"BrowserApp": {"core_mode": True}}, "Start the app in core mode.") +test_flags["dev-mode"] = ({"BrowserApp": {"dev_mode": True}}, "Start the app in dev mode.") +test_flags["watch"] = ({"BrowserApp": {"watch": True}}, "Start the app in watch mode.") test_aliases = dict(aliases) -test_aliases['app-dir'] = 'BrowserApp.app_dir' +test_aliases["app-dir"] = "BrowserApp.app_dir" class LogErrorHandler(logging.Handler): @@ -56,7 +49,11 @@ def filter(self, record): # 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 isinstance(record.exc_info[1], (StreamClosedError, WebSocketClosedError)): + if ( + hasattr(record, "exc_info") + and record.exc_info is not None + and isinstance(record.exc_info[1], (StreamClosedError, WebSocketClosedError)) + ): return return super().filter(record) @@ -86,12 +83,12 @@ async def run_test_async(app, func): env_patch = TestEnv() env_patch.start() - app.log.info('Running async test') + app.log.info("Running async test") # The entry URL for browser tests is different in notebook >= 6.0, # since that uses a local HTML file to point the user at the app. - if hasattr(app, 'browser_open_file'): - url = urljoin('file:', pathname2url(https://github.com/app.browser_open_file)) + if hasattr(app, "browser_open_file"): + url = urljoin("file:", pathname2url(https://github.com/app.browser_open_file)) else: url = app.display_url @@ -99,14 +96,14 @@ async def run_test_async(app, func): if inspect.iscoroutinefunction(func): test = func(url) else: - app.log.info('Using thread pool executor to run test') + app.log.info("Using thread pool executor to run test") loop = asyncio.get_event_loop() executor = ThreadPoolExecutor() task = loop.run_in_executor(executor, func, url) test = asyncio.wait([task]) try: - await test + await test except Exception as e: app.log.critical("Caught exception during the test:") app.log.error(str(e)) @@ -116,11 +113,11 @@ async def run_test_async(app, func): result = 0 if handler.errored: result = 1 - app.log.critical('Exiting with 1 due to errors') + app.log.critical("Exiting with 1 due to errors") else: - app.log.info('Exiting normally') + app.log.info("Exiting normally") - app.log.info('Stopping server...') + app.log.info("Stopping server...") try: app.http_server.stop() app.io_loop.stop() @@ -135,111 +132,79 @@ async def run_test_async(app, func): async def run_async_process(cmd, **kwargs): """Run an asynchronous command""" - proc = await asyncio.create_subprocess_exec( - *cmd, - **kwargs) + proc = await asyncio.create_subprocess_exec(*cmd, **kwargs) stdout, stderr = await proc.communicate() if proc.returncode != 0: - raise RuntimeError(str(cmd) + ' exited with ' + str(proc.returncode)) + raise RuntimeError(str(cmd) + " exited with " + str(proc.returncode)) return stdout, stderr async def run_browser(url): - """Run the browser test and return an exit code. - """ - target = osp.join(get_app_dir(), 'browser_test') - if not osp.exists(osp.join(target, 'node_modules')): + """Run the browser test and return an exit code.""" + target = osp.join(get_app_dir(), "browser_test") + 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) - shutil.copy(osp.join(here, 'browser-test.js'), osp.join(target, 'browser-test.js')) + 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) def run_browser_sync(url): - """Run the browser test and return an exit code. - """ - target = osp.join(get_app_dir(), 'browser_test') - if not osp.exists(osp.join(target, 'node_modules')): + """Run the browser test and return an exit code.""" + 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) - shutil.copy(osp.join(here, 'browser-test.js'), osp.join(target, 'browser-test.js')) + 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) + class BrowserApp(LabApp): """An app the launches JupyterLab and waits for it to start up, checking for JS console errors, JS errors, and Python logged errors. """ + name = __name__ open_browser = False - serverapp_config = { - "base_url": "/foo/" - } - default_url = "/lab?reset" - ip = '127.0.0.1' + serverapp_config = {"base_url": "/foo/"} + default_url = "/doc?reset" + 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['page_config_data']['browserTest'] = True - self.settings['page_config_data']['buildAvailable'] = False - self.settings['page_config_data']['exposeAppInBrowser'] = True + self.settings.setdefault("page_config_data", dict()) + self.settings["page_config_data"]["browserTest"] = True + self.settings["page_config_data"]["buildAvailable"] = False + self.settings["page_config_data"]["exposeAppInBrowser"] = True super().initialize_settings() def initialize_handlers(self): func = run_browser if self.test_browser else lambda url: 0 - if os.name == 'nt' and func == run_browser: + if os.name == "nt" and func == run_browser: func = run_browser_sync run_test(self.serverapp, func) super().initialize_handlers() 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): - extension = BrowserApp() - extension.serverapp = serverapp - extension.load_config_file() - extension.update_config(serverapp.config) - extension.parse_command_line(serverapp.extra_args) - extension.initialize() + return [{"module": __name__, "app": BrowserApp}] def _jupyter_server_extension_paths(): - return [ - { - 'module': 'jupyterlab.browser_check' - } - ] + return [{"module": "jupyterlab.browser_check"}] -if __name__ == '__main__': +if __name__ == "__main__": skip_options = ["--no-browser-test", "--no-chrome-test"] for option in skip_options: if option in sys.argv: 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() diff --git a/jupyterlab/commands.py b/jupyterlab/commands.py index 0859922..1dc9c35 100644 --- a/jupyterlab/commands.py +++ b/jupyterlab/commands.py @@ -13,12 +13,11 @@ import os.path as osp import re import shutil -import stat import site +import stat import subprocess import sys import tarfile -import warnings from copy import deepcopy from glob import glob from pathlib import Path @@ -28,44 +27,50 @@ from urllib.request import Request, quote, urljoin, urlopen from jupyter_core.paths import jupyter_config_path -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, - get_static_page_config, - write_page_config) +from jupyter_server.extension.serverextension import ( + GREEN_ENABLED, + GREEN_OK, + RED_DISABLED, + RED_X, +) +from jupyterlab_server.config import ( + get_federated_extensions, + get_package_url, + get_page_config, + get_static_page_config, + write_page_config, +) 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 from jupyterlab.jlpmapp import HERE, YARN_PATH from jupyterlab.semver import Range, gt, gte, lt, lte, make_semver -from jupyterlab._version import __version__ # The regex for expecting the webpack output. -WEBPACK_EXPECT = re.compile(r'.*theme-light-extension/style/theme.css') +WEBPACK_EXPECT = re.compile(r".*theme-light-extension/style/theme.css") # The repo root directory -REPO_ROOT = osp.abspath(osp.join(HERE, '..')) +REPO_ROOT = osp.abspath(osp.join(HERE, "..")) # The dev mode directory. -DEV_DIR = osp.join(REPO_ROOT, 'dev_mode') +DEV_DIR = osp.join(REPO_ROOT, "dev_mode") # If we are pinning the package, rename it `pin@` -PIN_PREFIX = 'pin@' +PIN_PREFIX = "pin@" # Default Yarn registry used in default yarn.lock -YARN_DEFAULT_REGISTRY = 'https://registry.yarnpkg.com/' +YARN_DEFAULT_REGISTRY = "https://registry.yarnpkg.com/" class ProgressProcess(Process): - - def __init__(self, cmd, logger=None, cwd=None, kill_event=None, - env=None): + def __init__(self, cmd, logger=None, cwd=None, kill_event=None, env=None): """Start a subprocess that can be run asynchronously. Parameters @@ -82,15 +87,15 @@ def __init__(self, cmd, logger=None, cwd=None, kill_event=None, The environment for the process. """ if not isinstance(cmd, (list, tuple)): - raise ValueError('Command must be given as a list') + raise ValueError("Command must be given as a list") if kill_event and kill_event.is_set(): - raise ValueError('Process aborted') + raise ValueError("Process aborted") self.logger = _ensure_logger(logger) - self._last_line = '' + self._last_line = "" self.cmd = cmd - self.logger.debug('> ' + list2cmdline(cmd)) + self.logger.debug(f"> {list2cmdline(cmd)}") self.proc = self._create_process( cwd=cwd, @@ -98,7 +103,7 @@ def __init__(self, cmd, logger=None, cwd=None, kill_event=None, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True, - encoding='utf-8', + encoding="utf-8", ) self._kill_event = kill_event or Event() @@ -108,75 +113,69 @@ def wait(self): cache = [] proc = self.proc kill_event = self._kill_event - spinner = itertools.cycle(['-', '\\', '|', '/']) + spinner = itertools.cycle(["-", "\\", "|", "/"]) while proc.poll() is None: - sys.stdout.write(next(spinner)) # write the next character - sys.stdout.flush() # flush stdout buffer (actual character display) - sys.stdout.write('\b') + sys.stdout.write(next(spinner)) # write the next character + sys.stdout.flush() # flush stdout buffer (actual character display) + sys.stdout.write("\b") if kill_event.is_set(): self.terminate() - raise ValueError('Process was aborted') + raise ValueError("Process was aborted") try: - out, _ = proc.communicate(timeout=.1) + out, _ = proc.communicate(timeout=0.1) cache.append(out) except subprocess.TimeoutExpired: continue - self.logger.debug('\n'.join(cache)) + self.logger.debug("\n".join(cache)) sys.stdout.flush() return self.terminate() def pjoin(*args): - """Join paths to create a real path. - """ + """Join paths to create a real path.""" return osp.abspath(osp.join(*args)) def get_user_settings_dir(): - """Get the configured JupyterLab user settings directory. - """ - settings_dir = os.environ.get('JUPYTERLAB_SETTINGS_DIR') - settings_dir = settings_dir or pjoin( - jupyter_config_path()[0], 'lab', 'user-settings' - ) + """Get the configured JupyterLab user settings directory.""" + settings_dir = os.environ.get("JUPYTERLAB_SETTINGS_DIR") + settings_dir = settings_dir or pjoin(jupyter_config_path()[0], "lab", "user-settings") return osp.abspath(settings_dir) def get_workspaces_dir(): - """Get the configured JupyterLab workspaces directory. - """ - workspaces_dir = os.environ.get('JUPYTERLAB_WORKSPACES_DIR') - workspaces_dir = workspaces_dir or pjoin( - jupyter_config_path()[0], 'lab', 'workspaces' - ) + """Get the configured JupyterLab workspaces directory.""" + workspaces_dir = os.environ.get("JUPYTERLAB_WORKSPACES_DIR") + workspaces_dir = workspaces_dir or pjoin(jupyter_config_path()[0], "lab", "workspaces") return osp.abspath(workspaces_dir) def get_app_dir(): - """Get the configured JupyterLab app directory. - """ + """Get the configured JupyterLab app directory.""" # Default to the override environment variable. - if os.environ.get('JUPYTERLAB_DIR'): + if os.environ.get("JUPYTERLAB_DIR"): # We must resolve the path to get the canonical case of the path for # case-sensitive systems - return str(Path(os.environ['JUPYTERLAB_DIR']).resolve()) + return str(Path(os.environ["JUPYTERLAB_DIR"]).resolve()) # Use the default locations for data_files. - app_dir = pjoin(sys.prefix, 'share', 'jupyter', 'lab') + app_dir = pjoin(sys.prefix, "share", "jupyter", "lab") # Check for a user level install. # Ensure that USER_BASE is defined - if hasattr(site, 'getuserbase'): + if hasattr(site, "getuserbase"): site.getuserbase() - userbase = getattr(site, 'USER_BASE', None) + userbase = getattr(site, "USER_BASE", None) if HERE.startswith(userbase) and not app_dir.startswith(userbase): - app_dir = pjoin(userbase, 'share', 'jupyter', 'lab') + app_dir = pjoin(userbase, "share", "jupyter", "lab") # Check for a system install in '/usr/local/share'. - elif (sys.prefix.startswith('/usr') and not - osp.exists(app_dir) and - osp.exists('/usr/local/share/jupyter/lab')): - app_dir = '/usr/local/share/jupyter/lab' + elif ( + sys.prefix.startswith("/usr") + and not osp.exists(app_dir) + and osp.exists("/usr/local/share/jupyter/lab") + ): + app_dir = "/usr/local/share/jupyter/lab" # We must resolve the path to get the canonical case of the path for # case-sensitive systems @@ -184,20 +183,24 @@ def get_app_dir(): def dedupe_yarn(path, logger=None): - """ `yarn-deduplicate` with the `fewer` strategy to minimize total - packages installed in a given staging directory + """`yarn-deduplicate` with the `fewer` strategy to minimize total + packages installed in a given staging directory - This means a extension (or dependency) _could_ cause a downgrade of an - version expected at publication time, but core should aggressively set - pins above, for example, known-bad versions + This means a extension (or dependency) _could_ cause a downgrade of an + version expected at publication time, but core should aggressively set + pins above, for example, known-bad versions """ - had_dupes = ProgressProcess( - ['node', YARN_PATH, 'yarn-deduplicate', '-s', 'fewer', '--fail'], - cwd=path, logger=logger - ).wait() != 0 + had_dupes = ( + ProgressProcess( + ["node", YARN_PATH, "yarn-deduplicate", "-s", "fewer", "--fail"], + cwd=path, + logger=logger, + ).wait() + != 0 + ) if had_dupes: - yarn_proc = ProgressProcess(['node', YARN_PATH], cwd=path, logger=logger) + yarn_proc = ProgressProcess(["node", YARN_PATH], cwd=path, logger=logger) yarn_proc.wait() @@ -207,12 +210,14 @@ def ensure_node_modules(cwd, logger=None): Returns true if the node_modules was updated. """ logger = _ensure_logger(logger) - yarn_proc = ProgressProcess(['node', YARN_PATH, 'check', '--verify-tree'], cwd=cwd, logger=logger) + yarn_proc = ProgressProcess( + ["node", YARN_PATH, "check", "--verify-tree"], cwd=cwd, logger=logger + ) ret = yarn_proc.wait() # Update node_modules if needed. if ret != 0: - yarn_proc = ProgressProcess(['node', YARN_PATH], cwd=cwd, logger=logger) + yarn_proc = ProgressProcess(["node", YARN_PATH], cwd=cwd, logger=logger) yarn_proc.wait() dedupe_yarn(REPO_ROOT, logger) @@ -220,30 +225,26 @@ def ensure_node_modules(cwd, logger=None): def ensure_dev(logger=None): - """Ensure that the dev assets are available. - """ + """Ensure that the dev assets are available.""" logger = _ensure_logger(logger) - target = pjoin(DEV_DIR, 'static') + target = pjoin(DEV_DIR, "static") # Determine whether to build. if ensure_node_modules(REPO_ROOT, logger) or not osp.exists(target): - yarn_proc = ProgressProcess(['node', YARN_PATH, 'build'], cwd=REPO_ROOT, - logger=logger) + yarn_proc = ProgressProcess(["node", YARN_PATH, "build"], cwd=REPO_ROOT, logger=logger) yarn_proc.wait() def ensure_core(logger=None): - """Ensure that the core assets are available. - """ - staging = pjoin(HERE, 'staging') + """Ensure that the core assets are available.""" + staging = pjoin(HERE, "staging") logger = _ensure_logger(logger) # Determine whether to build. - target = pjoin(HERE, 'static', 'index.html') + target = pjoin(HERE, "static", "index.html") if not osp.exists(target): ensure_node_modules(staging, logger) - yarn_proc = ProgressProcess(['node', YARN_PATH, 'build'], cwd=staging, - logger=logger) + yarn_proc = ProgressProcess(["node", YARN_PATH, "build"], cwd=staging, logger=logger) yarn_proc.wait() @@ -252,11 +253,13 @@ def ensure_app(app_dir): If it does not exist, return a list of messages to prompt the user. """ - if osp.exists(pjoin(app_dir, 'static', 'index.html')): + if osp.exists(pjoin(app_dir, "static", "index.html")): return - msgs = ['JupyterLab application assets not found in "%s"' % app_dir, - 'Please run `jupyter lab build` or use a different app directory'] + msgs = [ + 'JupyterLab application assets not found in "%s"' % app_dir, + "Please run `jupyter lab build` or use a different app directory", + ] return msgs @@ -275,12 +278,13 @@ def watch_packages(logger=None): logger = _ensure_logger(logger) ensure_node_modules(REPO_ROOT, logger) - ts_dir = osp.abspath(osp.join(REPO_ROOT, 'packages', 'metapackage')) + ts_dir = osp.abspath(osp.join(REPO_ROOT, "packages", "metapackage")) # Run typescript watch and wait for the string indicating it is done. - ts_regex = r'.* Found 0 errors\. Watching for file changes\.' - ts_proc = WatchHelper(['node', YARN_PATH, 'run', 'watch'], - cwd=ts_dir, logger=logger, startup_regex=ts_regex) + ts_regex = r".* Found 0 errors\. Watching for file changes\." + ts_proc = WatchHelper( + ["node", YARN_PATH, "run", "watch"], cwd=ts_dir, logger=logger, startup_regex=ts_regex + ) return [ts_proc] @@ -302,9 +306,12 @@ def watch_dev(logger=None): package_procs = watch_packages(logger) # Run webpack watch and wait for compilation. - wp_proc = WatchHelper(['node', YARN_PATH, 'run', 'watch'], - cwd=DEV_DIR, logger=logger, - startup_regex=WEBPACK_EXPECT) + wp_proc = WatchHelper( + ["node", YARN_PATH, "run", "watch"], + cwd=DEV_DIR, + logger=logger, + startup_regex=WEBPACK_EXPECT, + ) return package_procs + [wp_proc] @@ -314,50 +321,60 @@ class AppOptions(HasTraits): def __init__(self, logger=None, core_config=None, **kwargs): if core_config is not None: - kwargs['core_config'] = core_config + kwargs["core_config"] = core_config if logger is not None: - kwargs['logger'] = logger + kwargs["logger"] = logger # use the default if app_dir is empty - if 'app_dir' in kwargs and not kwargs['app_dir']: - kwargs.pop('app_dir') + if "app_dir" in kwargs and not kwargs["app_dir"]: + kwargs.pop("app_dir") super(AppOptions, self).__init__(**kwargs) - app_dir = Unicode(help='The application directory') + 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') + logger = Instance(logging.Logger, help="The logger to use") - core_config = Instance(CoreConfig, help='Configuration for core data') + core_config = Instance(CoreConfig, help="Configuration for core data") - kill_event = Instance(Event, args=(), help='Event for aborting call') + kill_event = Instance(Event, args=(), help="Event for aborting call") - labextensions_path = List(Unicode(), help='The paths to look in for prebuilt JupyterLab extensions') + labextensions_path = List( + Unicode(), help="The paths to look in for prebuilt JupyterLab extensions" + ) registry = Unicode(help="NPM packages registry URL") splice_source = Bool(False, help="Splice source packages into app directory.") - @default('logger') + skip_full_build_check = Bool( + False, + help=( + "If true, perform only a quick check that the lab build is up to date." + " If false, perform a thorough check, which verifies extension contents." + ), + ) + + @default("logger") def _default_logger(self): - return logging.getLogger('jupyterlab') + return logging.getLogger("jupyterlab") # These defaults need to be federated to pick up # any changes to env vars: - @default('app_dir') + @default("app_dir") def _default_app_dir(self): return get_app_dir() - @default('core_config') + @default("core_config") def _default_core_config(self): return CoreConfig() - @default('registry') + @default("registry") def _default_registry(self): config = _yarn_config(self.logger)["yarn config"] return config.get("registry", YARN_DEFAULT_REGISTRY) @@ -397,7 +414,6 @@ def watch(app_options=None): return package_procs + handler.watch() - def install_extension(extension, app_options=None, pin=None): """Install an extension package into JupyterLab. @@ -441,57 +457,67 @@ 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') - if app_dir == pjoin(HERE, 'core'): - raise ValueError('Cannot clean the core app') + logger.info("Cleaning %s...", app_dir) + if app_dir == pjoin(HERE, "dev"): + raise ValueError("Cannot clean the dev app") + if app_dir == pjoin(HERE, "core"): + raise ValueError("Cannot clean the core app") - if getattr(app_options, 'all', False): - logger.info('Removing everything in %s...', app_dir) + 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'] + possibleTargets = ["extensions", "settings", "staging", "static"] targets = [t for t in possibleTargets if getattr(app_options, t)] for name in targets: target = pjoin(app_dir, name) if osp.exists(target): - logger.info('Removing %s...', name) + logger.info("Removing %s...", name) _rmtree(target, logger) else: - logger.info('%s not present, skipping...', name) - - logger.info('Success!') - if getattr(app_options, 'all', False) or getattr(app_options, 'extensions', False): - logger.info('All of your extensions have been removed, and will need to be reinstalled') - - -def build(name=None, version=None, static_url=None, - kill_event=None, - clean_staging=False, app_options=None, production=True, minimize=True): - """Build the JupyterLab application. - """ + logger.info("%s not present, skipping...", name) + + logger.info("Success!") + if getattr(app_options, "all", False) or getattr(app_options, "extensions", False): + logger.info("All of your extensions have been removed, and will need to be reinstalled") + + +def build( + name=None, + version=None, + static_url=None, + kill_event=None, + clean_staging=False, + app_options=None, + production=True, + minimize=True, +): + """Build the JupyterLab application.""" app_options = _ensure_options(app_options) _node_check(app_options.logger) handler = _AppHandler(app_options) - return handler.build(name=name, version=version, static_url=static_url, - production=production, minimize=minimize, clean_staging=clean_staging) + return handler.build( + name=name, + version=version, + static_url=static_url, + production=production, + minimize=minimize, + clean_staging=clean_staging, + ) def get_app_info(app_options=None): - """Get a dictionary of information about the app. - """ + """Get a dictionary of information about the app.""" handler = _AppHandler(app_options) handler._ensure_disabled_info() return handler.info -def enable_extension(extension, app_options=None, level='sys_prefix'): +def enable_extension(extension, app_options=None, level="sys_prefix"): """Enable a JupyterLab extension. Returns `True` if a rebuild is recommended, `False` otherwise. @@ -500,7 +526,7 @@ def enable_extension(extension, app_options=None, level='sys_prefix'): return handler.toggle_extension(extension, False, level=level) -def disable_extension(extension, app_options=None, level='sys_prefix'): +def disable_extension(extension, app_options=None, level="sys_prefix"): """Disable a JupyterLab package. Returns `True` if a rebuild is recommended, `False` otherwise. @@ -510,8 +536,7 @@ def disable_extension(extension, app_options=None, level='sys_prefix'): def check_extension(extension, installed=False, app_options=None): - """Check if a JupyterLab extension is enabled or disabled. - """ + """Check if a JupyterLab extension is enabled or disabled.""" handler = _AppHandler(app_options) return handler.check_extension(extension, installed) @@ -528,8 +553,7 @@ def build_check(app_options=None): def list_extensions(app_options=None): - """List the extensions. - """ + """List the extensions.""" handler = _AppHandler(app_options) return handler.list_extensions() @@ -555,25 +579,21 @@ def unlink_package(package, app_options=None): def get_app_version(app_options=None): """Get the application version.""" handler = _AppHandler(app_options) - return handler.info['version'] + return handler.info["version"] def get_latest_compatible_package_versions(names, app_options=None): - """Get the latest compatible version of a list of packages. - """ + """Get the latest compatible version of a list of packages.""" handler = _AppHandler(app_options) return handler.latest_compatible_package_versions(names) def read_package(target): - """Read the package data in a given target tarball. - """ + """Read the package data in a given target tarball.""" tar = tarfile.open(target, "r") - f = tar.extractfile('package/package.json') - data = json.loads(f.read().decode('utf8')) - data['jupyterlab_extracted_files'] = [ - f.path[len('package/'):] for f in tar.getmembers() - ] + f = tar.extractfile("package/package.json") + data = json.loads(f.read().decode("utf8")) + data["jupyterlab_extracted_files"] = [f.path[len("package/") :] for f in tar.getmembers()] tar.close() return data @@ -584,10 +604,8 @@ def read_package(target): class _AppHandler(object): - def __init__(self, options): - """Create a new _AppHandler object - """ + """Create a new _AppHandler object""" options = _ensure_options(options) self._options = options self.app_dir = options.app_dir @@ -598,6 +616,7 @@ def __init__(self, options): self.labextensions_path = options.labextensions_path self.kill_event = options.kill_event self.registry = options.registry + self.skip_full_build_check = options.skip_full_build_check # Do this last since it relies on other attributes self.info = self._get_app_info() @@ -610,16 +629,16 @@ def install_extension(self, extension, existing=None, pin=None): Returns `True` if a rebuild is recommended, `False` otherwise. """ extension = _normalize_path(extension) - extensions = self.info['extensions'] + extensions = self.info["extensions"] # Check for a core extensions. - if extension in self.info['core_extensions']: + if extension in self.info["core_extensions"]: config = self._read_build_config() - uninstalled = config.get('uninstalled_core_extensions', []) + uninstalled = config.get("uninstalled_core_extensions", []) if extension in uninstalled: - self.logger.info('Installing core extension %s' % extension) + self.logger.info("Installing core extension %s" % extension) uninstalled.remove(extension) - config['uninstalled_core_extensions'] = uninstalled + config["uninstalled_core_extensions"] = uninstalled self._write_build_config(config) return True return False @@ -631,29 +650,35 @@ def install_extension(self, extension, existing=None, pin=None): with TemporaryDirectory() as tempdir: info = self._install_extension(extension, tempdir, pin=pin) - name = info['name'] + name = info["name"] # Local directories get name mangled and stored in metadata. - if info['is_dir']: + if info["is_dir"]: config = self._read_build_config() - local = config.setdefault('local_extensions', dict()) - local[name] = info['source'] + local = config.setdefault("local_extensions", {}) + local[name] = info["source"] self._write_build_config(config) # Remove an existing extension with the same name and different path if name in extensions: other = extensions[name] - if other['path'] != info['path'] and other['location'] == 'app': - os.remove(other['path']) + if other["path"] != info["path"] and other["location"] == "app": + os.remove(other["path"]) return True - def build(self, name=None, version=None, static_url=None, - clean_staging=False, production=True, minimize=True): - """Build the application. - """ + def build( + self, + name=None, + version=None, + static_url=None, + clean_staging=False, + production=True, + minimize=True, + ): + """Build the application.""" if production is None: - production = not (self.info['linked_packages'] or self.info['local_extensions']) + production = not (self.info["linked_packages"] or self.info["local_extensions"]) if not production: minimize = False @@ -661,36 +686,35 @@ def build(self, name=None, version=None, static_url=None, # If splicing, make sure the source packages are built if self._options.splice_source: ensure_node_modules(REPO_ROOT, logger=self.logger) - self._run(['node', YARN_PATH, 'build:packages'], cwd=REPO_ROOT) + self._run(["node", YARN_PATH, "build:packages"], cwd=REPO_ROOT) - info = ['production' if production else 'development'] + info = ["production" if production else "development"] if production: - info.append('minimized' if minimize else 'not minimized') - self.logger.info(f'Building jupyterlab assets ({", ".join(info)})') + info.append("minimized" if minimize else "not minimized") + self.logger.info(f'Building ElixirNote assets ({", ".join(info)})') # Set up the build directory. app_dir = self.app_dir self._populate_staging( - name=name, version=version, static_url=static_url, - clean=clean_staging + name=name, version=version, static_url=static_url, clean=clean_staging ) - staging = pjoin(app_dir, 'staging') + 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", "--non-interactive"], cwd=staging) if ret != 0: - msg = 'npm dependencies failed to install' + msg = "npm dependencies failed to install" self.logger.debug(msg) raise RuntimeError(msg) # Build the app. dedupe_yarn(staging, self.logger) command = f'build:{"prod" if production else "dev"}{":minimize" if minimize else ""}' - ret = self._run(['node', YARN_PATH, 'run', command], cwd=staging) + ret = self._run(["node", YARN_PATH, "run", command], cwd=staging) if ret != 0: - msg = 'JupyterLab failed to build' + msg = "JupyterLab failed to build" self.logger.debug(msg) raise RuntimeError(msg) @@ -698,139 +722,148 @@ def watch(self): """Start the application watcher and then run the watch in the background. """ - staging = pjoin(self.app_dir, 'staging') + staging = pjoin(self.app_dir, "staging") self._populate_staging() # Make sure packages are installed. - self._run(['node', YARN_PATH, 'install'], cwd=staging) + self._run(["node", YARN_PATH, "install"], cwd=staging) dedupe_yarn(staging, self.logger) - proc = WatchHelper(['node', YARN_PATH, 'run', 'watch'], - cwd=pjoin(self.app_dir, 'staging'), - startup_regex=WEBPACK_EXPECT, - logger=self.logger) + proc = WatchHelper( + ["node", YARN_PATH, "run", "watch"], + cwd=pjoin(self.app_dir, "staging"), + startup_regex=WEBPACK_EXPECT, + logger=self.logger, + ) return [proc] def list_extensions(self): - """Print an output of the extensions. - """ + """Print an output of the extensions.""" self._ensure_disabled_info() logger = self.logger info = self.info - logger.info('JupyterLab v%s' % info['version']) + logger.info("JupyterLab v%s" % info["version"]) - if info['federated_extensions'] or info['extensions']: - info['compat_errors'] = self._get_extension_compat() + if info["federated_extensions"] or info["extensions"]: + info["compat_errors"] = self._get_extension_compat() - if info['federated_extensions']: + if info["federated_extensions"]: self._list_federated_extensions() - if info['extensions']: - logger.info('Other labextensions (built into JupyterLab)') - self._list_extensions(info, 'app') - self._list_extensions(info, 'sys') + if info["extensions"]: + logger.info("Other labextensions (built into JupyterLab)") + self._list_extensions(info, "app") + self._list_extensions(info, "sys") - local = info['local_extensions'] + local = info["local_extensions"] if local: - logger.info('\n local extensions:') + logger.info("\n local extensions:") for name in sorted(local): - logger.info(' %s: %s' % (name, local[name])) + logger.info(" %s: %s" % (name, local[name])) - linked_packages = info['linked_packages'] + linked_packages = info["linked_packages"] if linked_packages: - logger.info('\n linked packages:') + logger.info("\n linked packages:") for key in sorted(linked_packages): - source = linked_packages[key]['source'] - logger.info(' %s: %s' % (key, source)) + source = linked_packages[key]["source"] + logger.info(" %s: %s" % (key, source)) - uninstalled_core = info['uninstalled_core'] + uninstalled_core = info["uninstalled_core"] if uninstalled_core: - logger.info('\nUninstalled core extensions:') - [logger.info(' %s' % item) for item in sorted(uninstalled_core)] + logger.info("\nUninstalled core extensions:") + [logger.info(" %s" % item) for item in sorted(uninstalled_core)] - all_exts = list(info['federated_extensions']) + list(info['extensions']) + list(info['core_extensions']) + all_exts = ( + list(info["federated_extensions"]) + + list(info["extensions"]) + + list(info["core_extensions"]) + ) # Ignore disabled extensions that are not installed - disabled = [i for i in info['disabled'] if i.partition(':')[0] in all_exts] + disabled = [i for i in info["disabled"] if i.partition(":")[0] in all_exts] if disabled: - logger.info('\nDisabled extensions:') + logger.info("\nDisabled extensions:") 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)' - logger.info(' %s' % item) + item += " (all plugins)" + logger.info(" %s" % item) # Here check if modules are improperly shadowed improper_shadowed = [] - for ext_name in self.info['shadowed_exts']: - source_version = self.info['extensions'][ext_name]['version'] - prebuilt_version = self.info['federated_extensions'][ext_name]['version'] - if not gte(prebuilt_version, source_version, True): - improper_shadowed.append(ext_name) + for ext_name in self.info["shadowed_exts"]: + source_version = self.info["extensions"][ext_name]["version"] + prebuilt_version = self.info["federated_extensions"][ext_name]["version"] + if not gte(prebuilt_version, source_version, True): + improper_shadowed.append(ext_name) if improper_shadowed: - logger.info('\nThe following source extensions are overshadowed by older prebuilt extensions:') - [logger.info(' %s' % name) for name in sorted(improper_shadowed)] + logger.info( + "\nThe following source extensions are overshadowed by older prebuilt extensions:" + ) + [logger.info(" %s" % name) for name in sorted(improper_shadowed)] messages = self.build_check(fast=True) if messages: - logger.info('\nBuild recommended, please run `jupyter lab build`:') - [logger.info(' %s' % item) for item in messages] + logger.info("\nBuild recommended, please run `jupyter lab build`:") + [logger.info(" %s" % item) for item in messages] - def build_check(self, fast=False): + def build_check(self, fast=None): """Determine whether JupyterLab should be built. Returns a list of messages. """ + if fast is None: + fast = self.skip_full_build_check app_dir = self.app_dir - local = self.info['local_extensions'] - linked = self.info['linked_packages'] + local = self.info["local_extensions"] + linked = self.info["linked_packages"] messages = [] # Check for no application. - pkg_path = pjoin(app_dir, 'static', 'package.json') + pkg_path = pjoin(app_dir, "static", "package.json") if not osp.exists(pkg_path): - return ['No built application'] + return ["No built application"] - static_data = self.info['static_data'] - old_jlab = static_data['jupyterlab'] - old_deps = static_data.get('dependencies', dict()) + static_data = self.info["static_data"] + old_jlab = static_data["jupyterlab"] + old_deps = static_data.get("dependencies", {}) # Look for mismatched version. - static_version = old_jlab.get('version', '') - if not static_version.endswith('-spliced'): - core_version = old_jlab['version'] + static_version = old_jlab.get("version", "") + if not static_version.endswith("-spliced"): + core_version = old_jlab["version"] if Version(static_version) != Version(core_version): - msg = 'Version mismatch: %s (built), %s (current)' + msg = "Version mismatch: %s (built), %s (current)" return [msg % (static_version, core_version)] - shadowed_exts = self.info['shadowed_exts'] + shadowed_exts = self.info["shadowed_exts"] # 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_jlab = new_package["jupyterlab"] + new_deps = new_package.get("dependencies", {}) - for ext_type in ['extensions', 'mimeExtensions']: + for ext_type in ["extensions", "mimeExtensions"]: # Extensions that were added. for ext in new_jlab[ext_type]: if ext in shadowed_exts: continue if ext not in old_jlab[ext_type]: - messages.append('%s needs to be included in build' % ext) + messages.append("%s needs to be included in build" % ext) # Extensions that were removed. for ext in old_jlab[ext_type]: if ext in shadowed_exts: continue if ext not in new_jlab[ext_type]: - messages.append('%s needs to be removed from build' % ext) + messages.append("%s needs to be removed from build" % ext) # Look for mismatched dependencies - src_pkg_dir = pjoin(REPO_ROOT, 'packages') + src_pkg_dir = pjoin(REPO_ROOT, "packages") for (pkg, dep) in new_deps.items(): - if old_deps.get(pkg, '').startswith(src_pkg_dir): + if old_deps.get(pkg, "").startswith(src_pkg_dir): continue if pkg not in old_deps: continue @@ -838,24 +871,24 @@ def build_check(self, fast=False): if pkg in local or pkg in linked: continue if old_deps[pkg] != dep: - msg = '%s changed from %s to %s' + msg = "%s changed from %s to %s" messages.append(msg % (pkg, old_deps[pkg], new_deps[pkg])) # Look for updated local extensions. for (name, source) in local.items(): if fast or name in shadowed_exts: continue - dname = pjoin(app_dir, 'extensions') + dname = pjoin(app_dir, "extensions") if self._check_local(name, source, dname): - messages.append('%s content changed' % name) + messages.append("%s content changed" % name) # Look for updated linked packages. for (name, item) in linked.items(): if fast or name in shadowed_exts: continue - dname = pjoin(app_dir, 'staging', 'linked_packages') - if self._check_local(name, item['source'], dname): - messages.append('%s content changed' % name) + dname = pjoin(app_dir, "staging", "linked_packages") + if self._check_local(name, item["source"], dname): + messages.append("%s content changed" % name) return messages @@ -867,42 +900,52 @@ def uninstall_extension(self, name): info = self.info logger = self.logger - if name in info['federated_extensions']: - if info['federated_extensions'][name].get('install', dict()).get('uninstallInstructions', None): - logger.error('JupyterLab cannot uninstall this extension. %s' % info['federated_extensions'][name]['install']['uninstallInstructions']) + if name in info["federated_extensions"]: + if ( + info["federated_extensions"][name] + .get("install", {}) + .get("uninstallInstructions", None) + ): + logger.error( + "JupyterLab cannot uninstall this extension. %s" + % info["federated_extensions"][name]["install"]["uninstallInstructions"] + ) else: - logger.error('JupyterLab cannot uninstall %s since it was installed outside of JupyterLab. Use the same method used to install this extension to uninstall this extension.' % name) + logger.error( + "JupyterLab cannot uninstall %s since it was installed outside of JupyterLab. Use the same method used to install this extension to uninstall this extension." + % name + ) return False # Allow for uninstalled core extensions. - if name in info['core_extensions']: + if name in info["core_extensions"]: config = self._read_build_config() - uninstalled = config.get('uninstalled_core_extensions', []) + uninstalled = config.get("uninstalled_core_extensions", []) if name not in uninstalled: - logger.info('Uninstalling core extension %s' % name) + logger.info("Uninstalling core extension %s" % name) uninstalled.append(name) - config['uninstalled_core_extensions'] = uninstalled + config["uninstalled_core_extensions"] = uninstalled self._write_build_config(config) return True return False - local = info['local_extensions'] + local = info["local_extensions"] - for (extname, data) in info['extensions'].items(): - path = data['path'] + for (extname, data) in info["extensions"].items(): + path = data["path"] if extname == name: - msg = 'Uninstalling %s from %s' % (name, osp.dirname(path)) + msg = "Uninstalling %s from %s" % (name, 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", {}) 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): @@ -911,7 +954,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 @@ -922,8 +965,8 @@ def update_all_extensions(self): Returns `True` if a rebuild is recommended, `False` otherwise. """ should_rebuild = False - for (extname, _) in self.info['extensions'].items(): - if extname in self.info['local_extensions']: + for (extname, _) in self.info["extensions"].items(): + if extname in self.info["local_extensions"]: continue updated = self._update_extension(extname) # Rebuild if at least one update happens: @@ -935,7 +978,7 @@ def update_extension(self, name): Returns `True` if a rebuild is recommended, `False` otherwise. """ - if name not in self.info['extensions']: + if name not in self.info["extensions"]: self.logger.warning('No labextension named "%s" installed' % name) return False return self._update_extension(name) @@ -945,22 +988,22 @@ def _update_extension(self, name): Returns `True` if a rebuild is recommended, `False` otherwise. """ - data = self.info['extensions'][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("No compatible version found for %s!" % (name,)) return False - if latest == data['version']: - self.logger.info('Extension %r already up to date' % name) + 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("Updating %s to version %s" % (name, latest)) + return self.install_extension("%s@%s" % (name, latest)) def link_package(self, path): """Link a package at the given path. @@ -975,18 +1018,20 @@ def link_package(self, path): with TemporaryDirectory() as tempdir: info = self._extract_package(path, tempdir) - messages = _validate_extension(info['data']) + messages = _validate_extension(info["data"]) if not messages: return self.install_extension(path) # Warn that it is a linked package. - self.logger.warning('Installing %s as a linked package because it does not have extension metadata:', path) - [self.logger.warning(' %s' % m) for m in messages] + self.logger.warning( + "Installing %s as a linked package because it does not have extension metadata:", path + ) + [self.logger.warning(" %s" % m) for m in messages] # Add to metadata. config = self._read_build_config() - linked = config.setdefault('linked_packages', dict()) - linked[info['name']] = info['source'] + linked = config.setdefault("linked_packages", {}) + linked[info["name"]] = info["source"] self._write_build_config(config) return True @@ -1000,7 +1045,7 @@ 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(): @@ -1010,32 +1055,33 @@ def unlink_package(self, path): if found: del linked[found] else: - local = config.setdefault('local_extensions', dict()) + local = config.setdefault("local_extensions", {}) for (name, source) in local.items(): if name == path or source == path: found = name if found: del local[found] - path = self.info['extensions'][found]['path'] + path = self.info["extensions"][found]["path"] os.remove(path) if not found: - raise ValueError('No linked package for %s' % path) + raise ValueError("No linked package for %s" % path) self._write_build_config(config) return True - def toggle_extension(self, extension, value, level='sys_prefix'): + def toggle_extension(self, extension, value, level="sys_prefix"): """Enable or disable a lab extension. Returns `True` if a rebuild is recommended, `False` otherwise. """ - lab_config = LabConfig() - app_settings_dir = osp.join(self.app_dir, 'settings') + app_settings_dir = osp.join(self.app_dir, "settings") - page_config = get_static_page_config(app_settings_dir=app_settings_dir, logger=self.logger, level=level) + page_config = get_static_page_config( + app_settings_dir=app_settings_dir, logger=self.logger, level=level + ) - disabled = page_config.get('disabledExtensions', {}) + disabled = page_config.get("disabledExtensions", {}) did_something = False is_disabled = disabled.get(extension, False) if value and not is_disabled: @@ -1046,312 +1092,310 @@ def toggle_extension(self, extension, value, level='sys_prefix'): did_something = True if did_something: - page_config['disabledExtensions'] = disabled + page_config["disabledExtensions"] = disabled write_page_config(page_config, level=level) return did_something def check_extension(self, extension, check_installed_only=False): - """Check if a lab extension is enabled or disabled - """ + """Check if a lab extension is enabled or disabled""" self._ensure_disabled_info() info = self.info if extension in info["core_extensions"]: - return self._check_core_extension( - extension, info, check_installed_only) + 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("%s:%s" % (extension, GREEN_ENABLED)) return True - return self._check_common_extension( - extension, info, check_installed_only) + return self._check_common_extension(extension, info, check_installed_only) 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)) + """Check if a core extension is enabled or disabled""" + if extension in info["uninstalled_core"]: + self.logger.info("%s:%s" % (extension, RED_X)) return False if check_installed_only: - self.logger.info('%s: %s' % (extension, GREEN_OK)) + self.logger.info("%s: %s" % (extension, GREEN_OK)) return True - if extension in info['disabled_core']: - self.logger.info('%s: %s' % (extension, RED_DISABLED)) + if extension in info["disabled_core"]: + self.logger.info("%s: %s" % (extension, RED_DISABLED)) return False - self.logger.info('%s:%s' % (extension, GREEN_ENABLED)) + self.logger.info("%s:%s" % (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)) + """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)) return False errors = self._get_extension_compat()[extension] if errors: - self.logger.info('%s:%s (compatibility errors)' % - (extension, RED_X)) + self.logger.info("%s:%s (compatibility errors)" % (extension, RED_X)) return False if check_installed_only: - self.logger.info('%s: %s' % (extension, GREEN_OK)) + self.logger.info("%s: %s" % (extension, GREEN_OK)) return True - if _is_disabled(extension, info['disabled']): - self.logger.info('%s: %s' % (extension, RED_DISABLED)) + if _is_disabled(extension, info["disabled"]): + self.logger.info("%s: %s" % (extension, RED_DISABLED)) return False - self.logger.info('%s:%s' % (extension, GREEN_ENABLED)) + self.logger.info("%s:%s" % (extension, GREEN_ENABLED)) return True def _get_app_info(self): - """Get information about the app. - """ + """Get information about the app.""" - info = dict() - info['core_data'] = core_data = self.core_data - info['extensions'] = extensions = self._get_extensions(core_data) + info = {} + info["core_data"] = core_data = self.core_data + info["extensions"] = extensions = self._get_extensions(core_data) - info['local_extensions'] = self._get_local_extensions() - info['linked_packages'] = self._get_linked_packages() - info['app_extensions'] = app = [] - info['sys_extensions'] = sys = [] + info["local_extensions"] = self._get_local_extensions() + info["linked_packages"] = self._get_linked_packages() + info["app_extensions"] = app = [] + info["sys_extensions"] = sys = [] for (name, data) in extensions.items(): - data['is_local'] = name in info['local_extensions'] - if data['location'] == 'app': + data["is_local"] = name in info["local_extensions"] + if data["location"] == "app": app.append(name) else: sys.append(name) - info['uninstalled_core'] = self._get_uninstalled_core_extensions() + info["uninstalled_core"] = self._get_uninstalled_core_extensions() - info['static_data'] = _get_static_data(self.app_dir) - app_data = info['static_data'] or core_data - info['version'] = app_data['jupyterlab']['version'] - info['staticUrl'] = app_data['jupyterlab'].get('staticUrl', '') + info["static_data"] = _get_static_data(self.app_dir) + app_data = info["static_data"] or core_data + info["version"] = app_data["jupyterlab"]["version"] + info["staticUrl"] = app_data["jupyterlab"].get("staticUrl", "") - info['sys_dir'] = self.sys_dir - info['app_dir'] = self.app_dir + info["sys_dir"] = self.sys_dir + info["app_dir"] = self.app_dir - info['core_extensions'] = _get_core_extensions(self.core_data) + info["core_extensions"] = _get_core_extensions(self.core_data) - info['federated_extensions'] = get_federated_extensions(self.labextensions_path) - info['shadowed_exts'] = [ext for ext in info['extensions'] if ext in info['federated_extensions']] + info["federated_extensions"] = get_federated_extensions(self.labextensions_path) + info["shadowed_exts"] = [ + ext for ext in info["extensions"] if ext in info["federated_extensions"] + ] return info def _ensure_disabled_info(self): info = self.info - if 'disabled' in info: + if "disabled" in info: return labextensions_path = self.labextensions_path - app_settings_dir = osp.join(self.app_dir, 'settings') + app_settings_dir = osp.join(self.app_dir, "settings") - page_config = get_page_config(labextensions_path, app_settings_dir=app_settings_dir, logger=self.logger) + page_config = get_page_config( + labextensions_path, app_settings_dir=app_settings_dir, logger=self.logger + ) - disabled = page_config.get('disabledExtensions', {}) + disabled = page_config.get("disabledExtensions", {}) # handle disabledExtensions specified as a list (jupyterlab_server < 2.10) # see https://github.com/jupyterlab/jupyterlab_server/pull/192 for more info if isinstance(disabled, list): - disabled = { extension: True for extension in disabled } + disabled = {extension: True for extension in disabled} - info['disabled'] = disabled + info["disabled"] = disabled disabled_core = [] - for key in info['core_extensions']: - if key in info['disabled']: + for key in info["core_extensions"]: + if key in info["disabled"]: disabled_core.append(key) - info['disabled_core'] = disabled_core + info["disabled_core"] = disabled_core - def _populate_staging(self, name=None, version=None, static_url=None, - clean=False): - """Set up the assets in the staging directory. - """ + def _populate_staging(self, name=None, version=None, static_url=None, clean=False): + """Set up the assets in the staging directory.""" app_dir = self.app_dir - staging = pjoin(app_dir, 'staging') + staging = pjoin(app_dir, "staging") if clean and osp.exists(staging): self.logger.info("Cleaning %s", staging) _rmtree(staging, self.logger) self._ensure_app_dirs() if not version: - version = self.info['core_data']['jupyterlab']['version'] + version = self.info["core_data"]["jupyterlab"]["version"] splice_source = self._options.splice_source if splice_source: - self.logger.debug('Splicing dev packages into app directory.') + self.logger.debug("Splicing dev packages into app directory.") source_dir = DEV_DIR - version = __version__ + '-spliced' + version = __version__ + "-spliced" else: - source_dir = pjoin(HERE, 'staging') + source_dir = pjoin(HERE, "staging") # Look for mismatched version. - pkg_path = pjoin(staging, 'package.json') + pkg_path = pjoin(staging, "package.json") if osp.exists(pkg_path): with open(pkg_path) as fid: data = json.load(fid) - if data['jupyterlab'].get('version', '') != version: + if data["jupyterlab"].get("version", "") != version: _rmtree(staging, self.logger) os.makedirs(staging) - for fname in ['index.js', 'bootstrap.js', 'publicpath.js', - 'webpack.config.js', - 'webpack.prod.config.js', - 'webpack.prod.minimize.config.js']: + for fname in [ + "index.js", + "bootstrap.js", + "publicpath.js", + "webpack.config.js", + "webpack.prod.config.js", + "webpack.prod.minimize.config.js", + ]: target = pjoin(staging, fname) shutil.copy(pjoin(source_dir, fname), target) - for fname in ['.yarnrc', 'yarn.js']: + for fname in [".yarnrc", "yarn.js"]: target = pjoin(staging, fname) - shutil.copy(pjoin(HERE, 'staging', fname), target) + shutil.copy(pjoin(HERE, "staging", fname), target) # Ensure a clean templates directory - templates = pjoin(staging, 'templates') + templates = pjoin(staging, "templates") if osp.exists(templates): _rmtree(templates, self.logger) try: - shutil.copytree(pjoin(source_dir, 'templates'), templates) + shutil.copytree(pjoin(source_dir, "templates"), templates) except shutil.Error as error: # `copytree` throws an error if copying to + from NFS even though # the copy is successful (see https://bugs.python.org/issue24564 # and https://github.com/jupyterlab/jupyterlab/issues/5233) - real_error = '[Errno 22]' not in str(error) and '[Errno 5]' not in str(error) + real_error = "[Errno 22]" not in str(error) and "[Errno 5]" not in str(error) if real_error or not osp.exists(templates): raise # Ensure a clean linked packages directory. - linked_dir = pjoin(staging, 'linked_packages') + linked_dir = pjoin(staging, "linked_packages") if osp.exists(linked_dir): _rmtree(linked_dir, self.logger) os.makedirs(linked_dir) # Template the package.json file. # Update the local extensions. - extensions = self.info['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 continue - dname = pjoin(app_dir, 'extensions') - self._update_local(key, source, dname, extensions[key], - 'local_extensions') + dname = pjoin(app_dir, "extensions") + self._update_local(key, source, dname, extensions[key], "local_extensions") # Update the list of local extensions if any were removed. if removed: - self.info['local_extensions'] = self._get_local_extensions() + self.info["local_extensions"] = self._get_local_extensions() # Update the linked packages. - linked = self.info['linked_packages'] + linked = self.info["linked_packages"] for (key, item) in linked.items(): - dname = pjoin(staging, 'linked_packages') - self._update_local(key, item['source'], dname, item, - 'linked_packages') + dname = pjoin(staging, "linked_packages") + self._update_local(key, item["source"], dname, item, "linked_packages") # Then get the package template. data = self._get_package_template() - jlab = data['jupyterlab'] + jlab = data["jupyterlab"] if version: - jlab['version'] = version + jlab["version"] = version if name: - jlab['name'] = name + jlab["name"] = name if static_url: - jlab['staticUrl'] = static_url + jlab["staticUrl"] = static_url # Handle splicing of packages if splice_source: # Splice workspace tree as linked dependencies - for path in glob(pjoin(REPO_ROOT, 'packages', '*', 'package.json')): + for path in glob(pjoin(REPO_ROOT, "packages", "*", "package.json")): local_path = osp.dirname(osp.abspath(path)) - pkg_data = json.loads(Path(path).read_text(encoding='utf-8')) - name = pkg_data['name'] - if name in data['dependencies']: - data['dependencies'][name] = local_path - jlab['linkedPackages'][name] = local_path - if name in data['resolutions']: - data['resolutions'][name] = local_path + pkg_data = json.loads(Path(path).read_text(encoding="utf-8")) + name = pkg_data["name"] + if name in data["dependencies"]: + data["dependencies"][name] = local_path + jlab["linkedPackages"][name] = local_path + if name in data["resolutions"]: + data["resolutions"][name] = local_path # splice the builder as well - local_path = osp.abspath(pjoin(REPO_ROOT, 'builder')) - data['devDependencies']['@jupyterlab/builder'] = local_path - target = osp.join(staging, 'node_modules', '@jupyterlab', 'builder') + local_path = osp.abspath(pjoin(REPO_ROOT, "builder")) + data["devDependencies"]["@jupyterlab/builder"] = local_path + target = osp.join(staging, "node_modules", "@jupyterlab", "builder") # Remove node_modules so it gets re-populated - node_modules = pjoin(staging, 'node_modules') + node_modules = pjoin(staging, "node_modules") if osp.exists(node_modules): shutil.rmtree(node_modules, ignore_errors=True) # Write the package file - pkg_path = pjoin(staging, 'package.json') - with open(pkg_path, 'w') as fid: + pkg_path = pjoin(staging, "package.json") + with open(pkg_path, "w") as fid: json.dump(data, fid, indent=4) # 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: + 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: + with open(lock_path, "w", encoding="utf-8") as f: f.write(template) elif 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): - """Get the template the for staging package.json file. - """ + """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 - data = deepcopy(self.info['core_data']) - local = self.info['local_extensions'] - linked = self.info['linked_packages'] - extensions = self.info['extensions'] - shadowed_exts = self.info['shadowed_exts'] - jlab = data['jupyterlab'] + data = deepcopy(self.info["core_data"]) + local = self.info["local_extensions"] + linked = self.info["linked_packages"] + extensions = self.info["extensions"] + shadowed_exts = self.info["shadowed_exts"] + jlab = data["jupyterlab"] def format_path(path): - path = osp.relpath(path, pjoin(self.app_dir, 'staging')) - path = 'file:' + path.replace(os.sep, '/') - if os.name == 'nt': + path = osp.relpath(path, osp.abspath(osp.realpath(pjoin(self.app_dir, "staging")))) + path = "file:" + path.replace(os.sep, "/") + if os.name == "nt": path = path.lower() return path - jlab['linkedPackages'] = dict() + jlab["linkedPackages"] = {} # Handle local extensions. 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'] + jlab["linkedPackages"][key] = source + data["resolutions"][key] = "file:" + self.info["extensions"][key]["path"] # Handle linked packages. for (key, item) in linked.items(): if key in shadowed_exts: continue - path = pjoin(self.app_dir, 'staging', 'linked_packages') - path = pjoin(path, item['filename']) - data['dependencies'][key] = format_path(path) - jlab['linkedPackages'][key] = item['source'] - data['resolutions'][key] = format_path(path) + path = pjoin(self.app_dir, "staging", "linked_packages") + path = pjoin(path, item["filename"]) + data["dependencies"][key] = 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() @@ -1360,34 +1404,32 @@ def format_path(path): errors = compat_errors[key] if errors: if not silent: - _log_single_compat_errors( - logger, key, value['version'], errors - ) + _log_single_compat_errors(logger, key, value["version"], errors) continue - data['dependencies'][key] = format_path(value['path']) + data["dependencies"][key] = format_path(value["path"]) - jlab_data = value['jupyterlab'] - for item in ['extension', 'mimeExtension']: + jlab_data = value["jupyterlab"] + for item in ["extension", "mimeExtension"]: ext = jlab_data.get(item, False) if not ext: continue if ext is True: - ext = '' - jlab[item + 's'][key] = ext + ext = "" + jlab[item + "s"][key] = ext # Add metadata for the extension - data['jupyterlab']['extensionMetadata'][key] = jlab_data + data["jupyterlab"]["extensionMetadata"][key] = jlab_data # Handle uninstalled core extensions. - for item in self.info['uninstalled_core']: - if item in jlab['extensions']: - data['jupyterlab']['extensions'].pop(item) - elif item in jlab['mimeExtensions']: - data['jupyterlab']['mimeExtensions'].pop(item) + for item in self.info["uninstalled_core"]: + if item in jlab["extensions"]: + data["jupyterlab"]["extensions"].pop(item) + elif item in jlab["mimeExtensions"]: + data["jupyterlab"]["mimeExtensions"].pop(item) # Remove from dependencies as well. - if item in data['dependencies']: - data['dependencies'].pop(item) + if item in data["dependencies"]: + data["dependencies"].pop(item) return data @@ -1403,48 +1445,46 @@ def _check_local(self, name, source, dname): # This relies on `_extract_package` adding the hashsum # to the filename, allowing a simple exist check to # compare the hash to the "cache" in dname. - target = pjoin(dname, info['filename']) + target = pjoin(dname, info["filename"]) return not osp.exists(target) def _update_local(self, name, source, dname, data, dtype): - """Update a local dependency. Return `True` if changed. - """ + """Update a local dependency. Return `True` if changed.""" # Extract the package in a temporary directory. - existing = data['filename'] + existing = data["filename"] if not osp.exists(pjoin(dname, existing)): - existing = '' + existing = "" with TemporaryDirectory() as tempdir: info = self._extract_package(source, tempdir) # Bail if the file content has not changed. - if info['filename'] == existing: + if info["filename"] == existing: return existing - shutil.move(info['path'], pjoin(dname, info['filename'])) + shutil.move(info["path"], pjoin(dname, info["filename"])) # Remove the previous tarball and return the new file name. if existing: os.remove(pjoin(dname, existing)) - data['filename'] = info['filename'] - data['path'] = pjoin(data['tar_dir'], data['filename']) - return info['filename'] + data["filename"] = info["filename"] + data["path"] = pjoin(data["tar_dir"], data["filename"]) + return info["filename"] def _get_extensions(self, core_data): - """Get the extensions for the application. - """ + """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') - app_path = pjoin(self.app_dir, 'extensions') + sys_path = pjoin(self.sys_dir, "extensions") + app_path = pjoin(self.app_dir, "extensions") extensions = self._get_extensions_in_dir(self.sys_dir, core_data) # Look in app_dir if different. - app_path = pjoin(app_dir, 'extensions') + app_path = pjoin(app_dir, "extensions") if app_path == sys_path or not osp.exists(app_path): return extensions @@ -1453,92 +1493,89 @@ def _get_extensions(self, core_data): return extensions def _get_extensions_in_dir(self, dname, core_data): - """Get the extensions in a given directory. - """ - extensions = dict() - location = 'app' if dname == self.app_dir else 'sys' - for target in glob(pjoin(dname, 'extensions', '*.tgz')): + """Get the extensions in a given directory.""" + 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()) - name = data['name'] - jlab = data.get('jupyterlab', dict()) + deps = data.get("dependencies", {}) + name = data["name"] + jlab = data.get("jupyterlab", {}) path = osp.abspath(target) filename = osp.basename(target) if filename.startswith(PIN_PREFIX): - alias = filename[len(PIN_PREFIX):-len(".tgz")] + alias = filename[len(PIN_PREFIX) : -len(".tgz")] else: alias = None url = get_package_url(https://github.com/data) - extensions[alias or name] = dict(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) + extensions[alias or name] = dict( + 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, + ) return extensions def _get_extension_compat(self): - """Get the extension compatibility info. - """ - compat = dict() - core_data = self.info['core_data'] + """Get the extension compatibility info.""" + compat = {} + core_data = self.info["core_data"] seen = set() - for (name, data) in self.info['federated_extensions'].items(): - deps = data['dependencies'] + 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'] + deps = data["dependencies"] compat[name] = _validate_compatibility(name, deps, core_data) return compat def _get_local_extensions(self): - """Get the locally installed extensions. - """ - return self._get_local_data('local_extensions') + """Get the locally installed extensions.""" + return self._get_local_data("local_extensions") def _get_linked_packages(self): - """Get the linked packages. - """ - info = self._get_local_data('linked_packages') - dname = pjoin(self.app_dir, 'staging', 'linked_packages') + """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) + info[name] = dict(source=source, filename="", tar_dir=dname) if not osp.exists(dname): return info - for path in glob(pjoin(dname, '*.tgz')): + for path in glob(pjoin(dname, "*.tgz")): path = osp.abspath(path) data = read_package(path) - name = data['name'] + 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] - item['filename'] = osp.basename(path) - item['path'] = path - item['version'] = data['version'] - item['data'] = data + item["filename"] = osp.basename(path) + item["path"] = path + item["version"] = data["version"] + item["data"] = data return info def _get_uninstalled_core_extensions(self): - """Get the uninstalled core extensions. - """ + """Get the uninstalled core extensions.""" config = self._read_build_config() - return config.get('uninstalled_core_extensions', []) + return config.get("uninstalled_core_extensions", []) def _ensure_app_dirs(self): """Ensure that the application directories exist""" - dirs = ['extensions', 'settings', 'staging', 'schemas', 'themes'] + dirs = ["extensions", "settings", "staging", "schemas", "themes"] for dname in dirs: path = pjoin(self.app_dir, dname) if not osp.exists(path): @@ -1549,42 +1586,41 @@ def _ensure_app_dirs(self): raise def _list_extensions(self, info, ext_type): - """List the extensions of a given type. - """ + """List the extensions of a given type.""" self._ensure_disabled_info() logger = self.logger - names = info['%s_extensions' % ext_type] + names = info["%s_extensions" % ext_type] if not names: return - dname = info['%s_dir' % ext_type] + dname = info["%s_dir" % ext_type] error_accumulator = {} - logger.info(' %s dir: %s' % (ext_type, dname)) + logger.info(" %s dir: %s" % (ext_type, dname)) for name in sorted(names): - if name in info['federated_extensions']: + if name in info["federated_extensions"]: continue - data = info['extensions'][name] - version = data['version'] - errors = info['compat_errors'][name] - extra = '' - if _is_disabled(name, info['disabled']): - extra += ' %s' % RED_DISABLED + data = info["extensions"][name] + version = data["version"] + errors = info["compat_errors"][name] + extra = "" + if _is_disabled(name, info["disabled"]): + extra += " %s" % RED_DISABLED else: - extra += ' %s' % GREEN_ENABLED + extra += " %s" % GREEN_ENABLED if errors: - extra += ' %s' % RED_X + extra += " %s" % RED_X else: - extra += ' %s' % GREEN_OK - if data['is_local']: - extra += '*' + extra += " %s" % GREEN_OK + if data["is_local"]: + extra += "*" # 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'] + 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(" %s %s v%s%s" % (name, alias_package_source, version, extra)) else: - logger.info(' %s v%s%s' % (name, version, extra)) + logger.info(" %s v%s%s" % (name, version, extra)) if errors: error_accumulator[name] = (version, errors) @@ -1592,7 +1628,7 @@ def _list_extensions(self, info, ext_type): _log_multiple_compat_errors(logger, error_accumulator) # Write a blank line separator - logger.info('') + logger.info("") def _list_federated_extensions(self): self._ensure_disabled_info() @@ -1602,50 +1638,46 @@ def _list_federated_extensions(self): error_accumulator = {} ext_dirs = dict((p, False) for p in self.labextensions_path) - for value in info['federated_extensions'].values(): - ext_dirs[value['ext_dir']] = True + for value in info["federated_extensions"].values(): + ext_dirs[value["ext_dir"]] = True for ext_dir, has_exts in ext_dirs.items(): if not has_exts: continue logger.info(ext_dir) - for name in info['federated_extensions']: - data = info['federated_extensions'][name] - if data['ext_dir'] != ext_dir: + for name in info["federated_extensions"]: + data = info["federated_extensions"][name] + if data["ext_dir"] != ext_dir: continue - version = data['version'] - errors = info['compat_errors'][name] - extra = '' - if _is_disabled(name, info['disabled']): - extra += ' %s' % RED_DISABLED + version = data["version"] + errors = info["compat_errors"][name] + extra = "" + if _is_disabled(name, info["disabled"]): + extra += " %s" % RED_DISABLED else: - extra += ' %s' % GREEN_ENABLED + extra += " %s" % GREEN_ENABLED if errors: - extra += ' %s' % RED_X + extra += " %s" % RED_X else: - extra += ' %s' % GREEN_OK - if data['is_local']: - extra += '*' + extra += " %s" % GREEN_OK + if data["is_local"]: + extra += "*" - install = data.get('install') + install = data.get("install") if install: - extra += ' (%s, %s)' % ( - install['packageManager'], - install['packageName'] - ) - logger.info(' %s v%s%s' % (name, version, extra)) + extra += " (%s, %s)" % (install["packageManager"], install["packageName"]) + logger.info(" %s v%s%s" % (name, version, extra)) if errors: error_accumulator[name] = (version, errors) # Add a spacer line after - logger.info('') + logger.info("") # Write all errors at end: _log_multiple_compat_errors(logger, error_accumulator) def _read_build_config(self): - """Get the build config data for the app dir. - """ - target = pjoin(self.app_dir, 'settings', 'build_config.json') + """Get the build config data for the app dir.""" + target = pjoin(self.app_dir, "settings", "build_config.json") if not osp.exists(target): return {} else: @@ -1653,28 +1685,26 @@ def _read_build_config(self): return json.load(fid) def _write_build_config(self, config): - """Write the build config to the app dir. - """ + """Write the build config to the app dir.""" self._ensure_app_dirs() - target = pjoin(self.app_dir, 'settings', 'build_config.json') - with open(target, 'w') as fid: + target = pjoin(self.app_dir, "settings", "build_config.json") + with open(target, "w") as fid: json.dump(config, fid, indent=4) def _get_local_data(self, source): - """Get the local data for extensions or linked packages. - """ + """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(): if not osp.exists(source): dead.append(name) for name in dead: - link_type = source.replace('_', ' ') + link_type = source.replace("_", " ") msg = '**Note: Removing dead %s "%s"' % (link_type, name) - self.logger.warn(msg) + self.logger.warning(msg) del data[name] if dead: @@ -1683,23 +1713,22 @@ def _get_local_data(self, source): return data def _install_extension(self, extension, tempdir, pin=None): - """Install an extension with validation and return the name and path. - """ + """Install an extension with validation and return the name and path.""" info = self._extract_package(extension, tempdir, pin=pin) - data = info['data'] + data = info["data"] # Check for compatible version unless: # - A specific version was requested (@ in name, # but after first char to allow for scope marker). # - Package is locally installed. - allow_fallback = '@' not in extension[1:] and not info['is_dir'] - name = info['name'] + allow_fallback = "@" not in extension[1:] and not info["is_dir"] + name = info["name"] # Verify that the package is an extension. messages = _validate_extension(data) if messages: msg = '"%s" is not a valid extension:\n%s' - msg = msg % (extension, '\n'.join(messages)) + msg = msg % (extension, "\n".join(messages)) if allow_fallback: try: version = self._latest_compatible_package_version(name) @@ -1709,12 +1738,10 @@ def _install_extension(self, extension, tempdir, pin=None): 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 - ) + msg = _format_compatibility_errors(data["name"], data["version"], errors) if allow_fallback: try: version = self._latest_compatible_package_version(name) @@ -1723,29 +1750,25 @@ def _install_extension(self, extension, tempdir, pin=None): raise ValueError(msg) if version and name: - self.logger.debug('Incompatible extension:\n%s', name) - self.logger.debug('Found compatible version: %s', version) + 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("%s@%s" % (name, version), tempdir2) # Extend message to better guide the user what to do: - conflicts = '\n'.join(msg.splitlines()[2:]) - msg = ''.join(( - self._format_no_compatible_package_version(name), - "\n\n", - conflicts)) + conflicts = "\n".join(msg.splitlines()[2:]) + msg = "".join((self._format_no_compatible_package_version(name), "\n\n", conflicts)) raise ValueError(msg) # Move the file to the app directory. - target = pjoin(self.app_dir, 'extensions', info['filename']) + target = pjoin(self.app_dir, "extensions", info["filename"]) if osp.exists(target): os.remove(target) - shutil.move(info['path'], target) + shutil.move(info["path"], target) - info['path'] = target + info["path"] = target return info def _extract_package(self, source, tempdir, pin=None): @@ -1756,70 +1779,66 @@ def _extract_package(self, source, tempdir, pin=None): directory. """ is_dir = osp.exists(source) and osp.isdir(source) - if is_dir and not osp.exists(pjoin(source, 'node_modules')): - self._run(['node', YARN_PATH, 'install'], cwd=source) + 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) - ret = self._run([which('npm'), 'pack', source], cwd=tempdir) + ret = self._run([which("npm"), "pack", source], cwd=tempdir) if ret != 0: msg = '"%s" is not a valid npm package' raise ValueError(msg % source) - path = glob(pjoin(tempdir, '*.tgz'))[0] - info['data'] = read_package(path) + path = glob(pjoin(tempdir, "*.tgz"))[0] + info["data"] = read_package(path) if is_dir: - info['sha'] = sha = _tarsum(path) - target = path.replace('.tgz', '-%s.tgz' % sha) + info["sha"] = sha = _tarsum(path) + target = path.replace(".tgz", "-%s.tgz" % sha) shutil.move(path, target) - info['path'] = target + info["path"] = target else: - info['path'] = path + info["path"] = path if pin: - old_path = info['path'] - new_path = pjoin(osp.dirname(old_path), '{}{}.tgz'.format(PIN_PREFIX, pin)) + old_path = info["path"] + new_path = pjoin(osp.dirname(old_path), "{}{}.tgz".format(PIN_PREFIX, pin)) shutil.move(old_path, new_path) - info['path'] = new_path + info["path"] = new_path - info['filename'] = osp.basename(info['path']) - info['name'] = info['data']['name'] - info['version'] = info['data']['version'] + info["filename"] = osp.basename(info["path"]) + info["name"] = info["data"]["name"] + info["version"] = info["data"]["version"] return info - def _latest_compatible_package_version(self, name): """Get the latest compatible version of a package""" - core_data = self.info['core_data'] + core_data = self.info["core_data"] try: metadata = _fetch_package_metadata(self.registry, name, self.logger) except URLError: return - versions = metadata.get('versions', {}) + versions = metadata.get("versions", {}) # Sort pre-release first, as we will reverse the sort: 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): - deps = data.get('dependencies', {}) + for version, data in sorted(versions.items(), key=sort_key, reverse=True): + deps = data.get("dependencies", {}) errors = _validate_compatibility(name, deps, core_data) if not errors: # Found a compatible version # skip deprecated versions - if 'deprecated' in data: + if "deprecated" in data: self.logger.debug( - 'Disregarding compatible version of package as it is deprecated: %s@%s' + "Disregarding compatible version of package as it is deprecated: %s@%s" % (name, version) ) continue # Verify that the version is a valid extension. with TemporaryDirectory() as tempdir: - info = self._extract_package( - '%s@%s' % (name, version), tempdir) - if _validate_extension(info['data']): + info = self._extract_package("%s@%s" % (name, version), tempdir) + if _validate_extension(info["data"]): # Invalid, do not consider other versions return # Valid @@ -1831,7 +1850,7 @@ def latest_compatible_package_versions(self, names): Like _latest_compatible_package_version, but optimized for retrieving the latest version for several packages in one go. """ - core_data = self.info['core_data'] + core_data = self.info["core_data"] keys = [] for name in names: @@ -1839,49 +1858,48 @@ def latest_compatible_package_versions(self, names): metadata = _fetch_package_metadata(self.registry, name, self.logger) except URLError: continue - versions = metadata.get('versions', {}) + versions = metadata.get("versions", {}) # Sort pre-release first, as we will reverse the sort: 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): + for version, data in sorted(versions.items(), key=sort_key, reverse=True): # skip deprecated versions - if 'deprecated' in data: + if "deprecated" in data: continue - deps = data.get('dependencies', {}) + deps = data.get("dependencies", {}) errors = _validate_compatibility(name, deps, core_data) if not errors: # Found a compatible version - keys.append('%s@%s' % (name, version)) + keys.append("%s@%s" % (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) for key in keys: - fname = key[0].replace('@', '') + key[1:].replace('@', '-').replace('/', '-') + '.tgz' + fname = ( + key[0].replace("@", "") + key[1:].replace("@", "-").replace("/", "-") + ".tgz" + ) data = read_package(osp.join(tempdir, fname)) # Verify that the version is a valid extension. if not _validate_extension(data): # Valid - versions[data['name']] = data['version'] + versions[data["name"]] = data["version"] return versions def _format_no_compatible_package_version(self, name): """Get the latest compatible version of a package""" - core_data = self.info['core_data'] + core_data = self.info["core_data"] # Whether lab version is too new: lab_newer_than_latest = False # Whether the latest version of the extension depend on a "future" version @@ -1892,16 +1910,16 @@ def _format_no_compatible_package_version(self, name): except URLError: pass else: - versions = metadata.get('versions', {}) + versions = metadata.get("versions", {}) # Sort pre-release first, as we will reverse the sort: def sort_key(key_value): return _semver_key(key_value[0], prerelease_first=True) store = tuple(sorted(versions.items(), key=sort_key, reverse=True)) - latest_deps = store[0][1].get('dependencies', {}) - core_deps = core_data['resolutions'] - singletons = core_data['jupyterlab']['singletonPackages'] + latest_deps = store[0][1].get("dependencies", {}) + core_deps = core_data["resolutions"] + singletons = core_data["jupyterlab"]["singletonPackages"] for (key, value) in latest_deps.items(): if key in singletons: @@ -1915,15 +1933,22 @@ def sort_key(key_value): if lab_newer_than_latest: # All singleton deps in current version of lab are newer than those # in the latest version of the extension - return ("The extension \"%s\" does not yet support the current version of " - "JupyterLab.\n" % name) - + return ( + 'The extension "%s" does not yet support the current version of ' + "JupyterLab.\n" % name + ) - parts = ["No version of {extension} could be found that is compatible with " - "the current version of JupyterLab."] + parts = [ + "No version of {extension} could be found that is compatible with " + "the current version of JupyterLab." + ] if latest_newer_than_lab: - parts.extend(("However, it seems to support a new version of JupyterLab.", - "Consider upgrading JupyterLab.")) + parts.extend( + ( + "However, it seems to support a new version of JupyterLab.", + "Consider upgrading JupyterLab.", + ) + ) return " ".join(parts).format(extension=name) @@ -1933,27 +1958,30 @@ def _run(self, cmd, **kwargs): Returns the exit code. """ if self.kill_event.is_set(): - raise ValueError('Command was killed') + raise ValueError("Command was killed") - kwargs['logger'] = self.logger - kwargs['kill_event'] = self.kill_event + kwargs["logger"] = self.logger + kwargs["kill_event"] = self.kill_event proc = ProgressProcess(cmd, **kwargs) return proc.wait() def _node_check(logger): - """Check for the existence of nodejs with the correct version. - """ - node = which('node') + """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) - logger.debug(output.decode('utf-8')) + output = subprocess.check_output([node, "node-version-check.js"], cwd=HERE) + logger.debug(output.decode("utf-8")) except Exception: data = CoreConfig()._data - ver = data['engines']['node'] - msg = 'Please install nodejs %s before continuing. nodejs may be installed using conda or directly from the nodejs website.' % ver + ver = data["engines"]["node"] + msg = ( + "Please install nodejs %s before continuing. nodejs may be installed using conda or directly from the nodejs website." + % ver + ) raise ValueError(msg) + def _yarn_config(logger): """Get the yarn configuration. @@ -1963,14 +1991,16 @@ def _yarn_config(logger): """ configuration = {"yarn config": {}, "npm config": {}} try: - node = which('node') + node = which("node") except ValueError: # Node not found == user with no need for building jupyterlab logger.debug("NodeJS was not found. Yarn user configuration is ignored.") return configuration try: - output_binary = subprocess.check_output([node, YARN_PATH, 'config', 'list', '--json'], stderr=subprocess.PIPE, cwd=HERE) - output = output_binary.decode('utf-8') + output_binary = subprocess.check_output( + [node, YARN_PATH, "config", "list", "--json"], stderr=subprocess.PIPE, cwd=HERE + ) + output = output_binary.decode("utf-8") lines = iter(output.splitlines()) try: for line in lines: @@ -1984,21 +2014,24 @@ def _yarn_config(logger): pass logger.debug("Yarn configuration loaded.") except subprocess.CalledProcessError as e: - logger.error("Fail to get yarn configuration. {!s}{!s}".format(e.stderr.decode('utf-8'), e.output.decode('utf-8'))) + logger.error( + "Fail to get yarn configuration. {!s}{!s}".format( + e.stderr.decode("utf-8"), e.output.decode("utf-8") + ) + ) except Exception as e: logger.error("Fail to get yarn configuration. {!s}".format(e)) - finally: - return configuration + + return configuration def _ensure_logger(logger=None): """Ensure that we have a logger""" - return logger or logging.getLogger('jupyterlab') + return logger or logging.getLogger("jupyterlab") def _normalize_path(extension): - """Normalize a given extension if it is a path. - """ + """Normalize a given extension if it is a path.""" extension = osp.expanduser(extension) if osp.exists(extension): extension = osp.abspath(extension) @@ -2007,8 +2040,9 @@ def _normalize_path(extension): def _rmtree(path, logger): """Remove a tree, logging errors""" + def onerror(*exc_info): - logger.debug('Error in shutil.rmtree', exc_info=exc_info) + logger.debug("Error in shutil.rmtree", exc_info=exc_info) shutil.rmtree(path, onerror=onerror) @@ -2018,7 +2052,7 @@ def _unlink(path, logger): try: os.unlink(path) except Exception: - logger.debug('Error in os.unlink', exc_info=sys.exc_info()) + logger.debug("Error in os.unlink", exc_info=sys.exc_info()) def _rmtree_star(path, logger): @@ -2036,38 +2070,38 @@ def _validate_extension(data): Returns any problems it finds. """ - jlab = data.get('jupyterlab', None) + jlab = data.get("jupyterlab", None) if jlab is None: - return ['No `jupyterlab` key'] + return ["No `jupyterlab` key"] if not isinstance(jlab, dict): - 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', '') + 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", "") messages = [] if not extension and not mime_extension: - messages.append('No `extension` or `mimeExtension` key present') + messages.append("No `extension` or `mimeExtension` key present") if extension == mime_extension: - msg = '`mimeExtension` and `extension` must point to different modules' + msg = "`mimeExtension` and `extension` must point to different modules" messages.append(msg) - files = data['jupyterlab_extracted_files'] - main = data.get('main', 'index.js') - if not main.endswith('.js'): - main += '.js' + files = data["jupyterlab_extracted_files"] + main = data.get("main", "index.js") + if not main.endswith(".js"): + main += ".js" if extension is True: extension = main - elif extension and not extension.endswith('.js'): - extension += '.js' + elif extension and not extension.endswith(".js"): + extension += ".js" if mime_extension is True: mime_extension = main - elif mime_extension and not mime_extension.endswith('.js'): - mime_extension += '.js' + elif mime_extension and not mime_extension.endswith(".js"): + mime_extension += ".js" if extension and extension not in files: messages.append('Missing extension module "%s"' % extension) @@ -2104,9 +2138,8 @@ def _tarsum(input_file): def _get_static_data(app_dir): - """Get the data for the app static dir. - """ - target = pjoin(app_dir, 'static', 'package.json') + """Get the data for the app static dir.""" + target = pjoin(app_dir, "static", "package.json") if osp.exists(target): with open(target) as fid: return json.load(fid) @@ -2115,10 +2148,9 @@ def _get_static_data(app_dir): def _validate_compatibility(extension, deps, core_data): - """Validate the compatibility of an extension. - """ - core_deps = core_data['resolutions'] - singletons = core_data['jupyterlab']['singletonPackages'] + """Validate the compatibility of an extension.""" + core_deps = core_data["resolutions"] + singletons = core_data["jupyterlab"]["singletonPackages"] errors = [] @@ -2140,8 +2172,9 @@ def _test_overlap(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False): Returns `None` if we cannot determine compatibility, otherwise whether there is an overlap """ - cmp = _compare_ranges(spec1, spec2, drop_prerelease1=drop_prerelease1, - drop_prerelease2=drop_prerelease2) + cmp = _compare_ranges( + spec1, spec2, drop_prerelease1=drop_prerelease1, drop_prerelease2=drop_prerelease2 + ) if cmp is None: return return cmp == 0 @@ -2174,16 +2207,16 @@ def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False y2 = r2set[-1].semver if x1.prerelease and drop_prerelease1: - x1 = x1.inc('patch') + x1 = x1.inc("patch") if y1.prerelease and drop_prerelease2: - y1 = y1.inc('patch') + y1 = y1.inc("patch") o1 = r1set[0].operator o2 = r2set[0].operator # We do not handle (<) specifiers. - if (o1.startswith('<') or o2.startswith('<')): + if o1.startswith("<") or o2.startswith("<"): continue # Handle single value specifiers. @@ -2196,16 +2229,21 @@ def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False def noop(x, y, z): return True - if x1 == x2 and o1.startswith('>'): + if x1 == x2 and o1.startswith(">"): lx = noop - if y1 == y2 and o2.startswith('>'): + if y1 == y2 and o2.startswith(">"): ly = noop # Check for overlap. - if (gte(x1, y1, True) and ly(x1, y2, True) or - gy(x2, y1, True) and ly(x2, y2, True) or - gte(y1, x1, True) and lx(y1, x2, True) or - gx(y2, x1, True) and lx(y2, x2, True) + if ( + gte(x1, y1, True) + and ly(x1, y2, True) + or gy(x2, y1, True) + and ly(x2, y2, True) + or gte(y1, x1, True) + and lx(y1, x2, True) + or gx(y2, x1, True) + and lx(y2, x2, True) ): # if we ever find an overlap, we can return immediately return 0 @@ -2227,7 +2265,7 @@ def noop(x, y, z): return_value = None continue - raise AssertionError('Unexpected case comparing version ranges') + raise AssertionError("Unexpected case comparing version ranges") if return_value is False: return_value = None @@ -2235,12 +2273,11 @@ def noop(x, y, z): def _is_disabled(name, disabled=None): - """Test whether the package is disabled. - """ + """Test whether the package is disabled.""" 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 @@ -2250,8 +2287,7 @@ def _is_disabled(name, disabled=None): def _format_compatibility_errors(name, version, errors): - """Format a message for compatibility errors. - """ + """Format a message for compatibility errors.""" msgs = [] l0 = 10 l1 = 10 @@ -2265,13 +2301,13 @@ def _format_compatibility_errors(name, version, errors): msg = '\n"%s@%s" is not compatible with the current JupyterLab' msg = msg % (name, version) - msg += '\nConflicting Dependencies:\n' - msg += 'JupyterLab'.ljust(l0) - msg += 'Extension'.ljust(l1) - msg += 'Package\n' + msg += "\nConflicting Dependencies:\n" + msg += "JupyterLab".ljust(l0) + msg += "Extension".ljust(l1) + msg += "Package\n" for (pkg, jlab, ext) in msgs: - msg += jlab.ljust(l0) + ext.ljust(l1) + pkg + '\n' + msg += jlab.ljust(l0) + ext.ljust(l1) + pkg + "\n" return msg @@ -2282,7 +2318,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) @@ -2290,17 +2326,21 @@ def _log_multiple_compat_errors(logger, errors_map): others.append(name) if outdated: - logger.warn('\n '.join( - ['\n The following extension are outdated:'] + - outdated + - ['\n Consider running "jupyter labextension update --all" ' - 'to check for updates.\n'] - )) + logger.warning( + "\n ".join( + ["\n The following extension are outdated:"] # noqa + + outdated # noqa + + [ # noqa + '\n Consider running "jupyter labextension update --all" ' + "to check for updates.\n" + ] + ) + ) 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): @@ -2308,14 +2348,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. @@ -2341,10 +2381,9 @@ def _compat_error_age(errors): def _get_core_extensions(core_data): - """Get the core extensions. - """ - data = core_data['jupyterlab'] - return list(data['extensions']) + list(data['mimeExtensions']) + """Get the core extensions.""" + data = core_data["jupyterlab"] + return list(data["extensions"]) + list(data["mimeExtensions"]) def _semver_prerelease_key(prerelease): @@ -2365,7 +2404,7 @@ def _semver_prerelease_key(prerelease): for entry in prerelease: if isinstance(entry, int): # Assure numerics always sort before string - yield ('', entry) + yield ("", entry) else: # Use ASCII compare: yield (entry,) @@ -2394,8 +2433,7 @@ def _semver_key(version, prerelease_first=False): # NOT having a prerelease is > having one key = key + (0,) if v.prerelease else (1,) if v.prerelease: - key = key + tuple(_semver_prerelease_key( - v.prerelease)) + key = key + tuple(_semver_prerelease_key(v.prerelease)) return key @@ -2403,25 +2441,22 @@ def _semver_key(version, prerelease_first=False): def _fetch_package_metadata(registry, name, logger): """Fetch the metadata for a package from the npm registry""" req = Request( - urljoin(registry, quote(name, safe='@')), + 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: - logger.debug('Fetching URL: %s' % (req.full_url)) + logger.debug("Fetching URL: %s" % (req.full_url)) except AttributeError: - logger.debug('Fetching URL: %s' % (req.get_full_url())) + logger.debug("Fetching URL: %s" % (req.get_full_url())) try: with contextlib.closing(urlopen(req)) as response: - return json.loads(response.read().decode('utf-8')) + return json.loads(response.read().decode("utf-8")) except URLError as exc: - logger.warning( - 'Failed to fetch package metadata for %r: %r', - name, exc) + logger.warning("Failed to fetch package metadata for %r: %r", name, exc) raise -if __name__ == '__main__': +if __name__ == "__main__": watch_dev(HERE) diff --git a/jupyterlab/coreconfig.py b/jupyterlab/coreconfig.py index ce7c547..8d9db27 100644 --- a/jupyterlab/coreconfig.py +++ b/jupyterlab/coreconfig.py @@ -10,21 +10,19 @@ def pjoin(*args): - """Join paths to create a real path. - """ + """Join paths to create a real path.""" return osp.abspath(osp.join(*args)) def _get_default_core_data(): - """Get the data for the app template. - """ - with open(pjoin(HERE, 'staging', 'package.json')) as fid: + """Get the data for the app template.""" + with open(pjoin(HERE, "staging", "package.json")) as fid: return json.load(fid) def _is_lab_package(name): """Whether a package name is in the lab namespace""" - return name.startswith('@jupyterlab/') + return name.startswith("@jupyterlab/") def _only_nonlab(collection): @@ -35,13 +33,10 @@ 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 dict((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') + raise TypeError("collection arg should be either dict or list/tuple") class CoreConfig: @@ -50,6 +45,7 @@ class CoreConfig: This enables custom lab application to override some parts of the core configuration of the build system. """ + def __init__(self): self._data = _get_default_core_data() @@ -70,23 +66,23 @@ def add(self, name, semver, extension=False, mime_extension=False): """ data = self._data if not name: - raise ValueError('Missing package name') + raise ValueError("Missing package name") if not semver: - raise ValueError('Missing package semver') - if name in data['resolutions']: - raise ValueError('Package already present: %r' % (name,)) - data['resolutions'][name] = semver + raise ValueError("Missing package semver") + if name in data["resolutions"]: + raise ValueError("Package already present: %r" % (name,)) + data["resolutions"][name] = semver # If both mimeExtension and extensions are True, treat # as mime extension if mime_extension: - data['jupyterlab']['mimeExtensions'][name] = "" - data['dependencies'][name] = semver + data["jupyterlab"]["mimeExtensions"][name] = "" + data["dependencies"][name] = semver elif extension: - data['jupyterlab']['extensions'][name] = "" - data['dependencies'][name] = semver + data["jupyterlab"]["extensions"][name] = "" + data["dependencies"][name] = semver else: - data['jupyterlab']['singletonPackages'].append(name) + data["jupyterlab"]["singletonPackages"].append(name) def remove(self, name): """Remove a package/extension. @@ -96,10 +92,10 @@ def remove(self, name): """ data = self._data maps = ( - data['dependencies'], - data['resolutions'], - data['jupyterlab']['extensions'], - data['jupyterlab']['mimeExtensions'], + data["dependencies"], + data["resolutions"], + data["jupyterlab"]["extensions"], + data["jupyterlab"]["mimeExtensions"], ) for m in maps: try: @@ -107,58 +103,56 @@ def remove(self, name): except KeyError: pass - data['jupyterlab']['singletonPackages'].remove(name) + data["jupyterlab"]["singletonPackages"].remove(name) def clear_packages(self, lab_only=True): - """Clear the packages/extensions. - """ + """Clear the packages/extensions.""" data = self._data # Clear all dependencies if lab_only: # Clear all "@jupyterlab/" dependencies - data['dependencies'] = _only_nonlab(data['dependencies']) - data['resolutions'] = _only_nonlab(data['resolutions']) - data['jupyterlab']['extensions'] = _only_nonlab( - data['jupyterlab']['extensions']) - data['jupyterlab']['mimeExtensions'] = _only_nonlab( - data['jupyterlab']['mimeExtensions']) - data['jupyterlab']['singletonPackages'] = _only_nonlab( - data['jupyterlab']['singletonPackages']) + data["dependencies"] = _only_nonlab(data["dependencies"]) + data["resolutions"] = _only_nonlab(data["resolutions"]) + data["jupyterlab"]["extensions"] = _only_nonlab(data["jupyterlab"]["extensions"]) + data["jupyterlab"]["mimeExtensions"] = _only_nonlab( + data["jupyterlab"]["mimeExtensions"] + ) + data["jupyterlab"]["singletonPackages"] = _only_nonlab( + data["jupyterlab"]["singletonPackages"] + ) else: - data['dependencies'] = {} - data['resolutions'] = {} - data['jupyterlab']['extensions'] = {} - data['jupyterlab']['mimeExtensions'] = {} - data['jupyterlab']['singletonPackages'] = [] + data["dependencies"] = {} + data["resolutions"] = {} + data["jupyterlab"]["extensions"] = {} + data["jupyterlab"]["mimeExtensions"] = {} + data["jupyterlab"]["singletonPackages"] = [] @property 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 dict((k, data["resolutions"][k]) for k in data["jupyterlab"]["extensions"].keys()) @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()) + (k, data["resolutions"][k]) for k in data["jupyterlab"]["mimeExtensions"].keys() + ) @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']) + (k, data["resolutions"].get(k, None)) for k in data["jupyterlab"]["singletonPackages"] + ) @property def static_dir(self): - return self._data['jupyterlab']['staticDir'] + return self._data["jupyterlab"]["staticDir"] @static_dir.setter def static_dir(self, static_dir): - self._data['jupyterlab']['staticDir'] = static_dir + self._data["jupyterlab"]["staticDir"] = static_dir diff --git a/jupyterlab/debuglog.py b/jupyterlab/debuglog.py index dd32f4a..68d97de 100644 --- a/jupyterlab/debuglog.py +++ b/jupyterlab/debuglog.py @@ -18,29 +18,28 @@ class DebugLogFileMixin(Configurable): - debug_log_path = Unicode('', config=True, help='Path to use for the debug log file') + debug_log_path = Unicode("", config=True, help="Path to use for the debug log file") @contextlib.contextmanager def debug_logging(self): log_path = self.debug_log_path if os.path.isdir(log_path): - log_path = os.path.join(log_path, 'jupyterlab-debug.log') + log_path = os.path.join(log_path, "jupyterlab-debug.log") if not log_path: - handle, log_path = tempfile.mkstemp(prefix='jupyterlab-debug-', suffix='.log') + handle, log_path = tempfile.mkstemp(prefix="jupyterlab-debug-", suffix=".log") os.close(handle) log = self.log # Transfer current log level to the handlers: for h in log.handlers: h.setLevel(self.log_level) - log.setLevel('DEBUG') + log.setLevel("DEBUG") # Create our debug-level file handler: - _debug_handler = logging.FileHandler( - log_path, 'w', 'utf8', delay=True) + _debug_handler = logging.FileHandler(log_path, "w", "utf8", delay=True) _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt) _debug_handler.setFormatter(_log_formatter) - _debug_handler.setLevel('DEBUG') + _debug_handler.setLevel("DEBUG") log.addHandler(_debug_handler) @@ -52,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) + print("An error occurred. See the log file for details: ", log_path) raise - print('An error occurred.') + print("An error occurred.") print(msg[-1].strip()) - print('See the log file for details: ', log_path) + print("See the log file for details: ", log_path) self.exit(1) else: log.removeHandler(_debug_handler) @@ -67,4 +66,3 @@ def debug_logging(self): except FileNotFoundError: pass log.removeHandler(_debug_handler) - diff --git a/jupyterlab/federated_labextensions.py b/jupyterlab/federated_labextensions.py index a95ee10..103eb8f 100644 --- a/jupyterlab/federated_labextensions.py +++ b/jupyterlab/federated_labextensions.py @@ -14,32 +14,43 @@ import shutil import subprocess import sys -from os.path import basename, join as pjoin, normpath -from jupyter_core.paths import ( - jupyter_data_dir, SYSTEM_JUPYTER_PATH, ENV_JUPYTER_PATH, -) +try: + from importlib.metadata import PackageNotFoundError, version +except ImportError: + from importlib_metadata import PackageNotFoundError, version +from os.path import basename +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 -from jupyterlab_server.config import get_federated_extensions from jupyter_server.extension.serverextension import ArgumentConflict +from jupyterlab_server.config import get_federated_extensions +from tomli import load from .commands import _test_overlap - DEPRECATED_ARGUMENT = object() HERE = osp.abspath(osp.dirname(__file__)) -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # Public API -#------------------------------------------------------------------------------ - -def develop_labextension(path, symlink=True, overwrite=False, - user=False, labextensions_dir=None, - destination=None, - logger=None, sys_prefix=False - ): +# ------------------------------------------------------------------------------ + + +def develop_labextension( + path, + symlink=True, + overwrite=False, + user=False, + labextensions_dir=None, + destination=None, + logger=None, + sys_prefix=False, +): """Install a prebuilt extension for JupyterLab Stages files and/or directories into the labextensions directory. @@ -73,12 +84,16 @@ def develop_labextension(path, symlink=True, overwrite=False, # the actual path to which we eventually installed full_dest = None - labext = _get_labextension_dir(user=user, sys_prefix=sys_prefix, labextensions_dir=labextensions_dir) + labext = _get_labextension_dir( + user=user, sys_prefix=sys_prefix, labextensions_dir=labextensions_dir + ) # make sure labextensions dir exists 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") + raise TypeError( + "path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions" + ) if not destination: destination = basename(normpath(path)) @@ -115,9 +130,9 @@ def develop_labextension(path, symlink=True, overwrite=False, raise ValueError("%s exists and is not a symlink" % full_dest) elif os.path.isdir(path): - path = pjoin(os.path.abspath(path), '') # end in path separator - for parent, dirs, files in os.walk(path): - dest_dir = pjoin(full_dest, parent[len(path):]) + path = pjoin(os.path.abspath(path), "") # end in path separator + for parent, _, files in os.walk(path): + dest_dir = pjoin(full_dest, parent[len(path) :]) if not os.path.exists(dest_dir): if logger: logger.info("Making directory: %s" % dest_dir) @@ -133,7 +148,15 @@ def develop_labextension(path, symlink=True, overwrite=False, return full_dest -def develop_labextension_py(module, user=False, sys_prefix=False, overwrite=True, symlink=True, labextensions_dir=None, logger=None): +def develop_labextension_py( + module, + user=False, + sys_prefix=False, + overwrite=True, + symlink=True, + labextensions_dir=None, + logger=None, +): """Develop a labextension bundled in a Python package. Returns a list of installed/updated directories. @@ -145,8 +168,8 @@ def develop_labextension_py(module, user=False, sys_prefix=False, overwrite=True full_dests = [] for labext in labexts: - src = os.path.join(base_path, labext['src']) - dest = labext['dest'] + src = os.path.join(base_path, labext["src"]) + dest = labext["dest"] if logger: logger.info("Installing %s -> %s" % (src, dest)) @@ -154,110 +177,135 @@ def develop_labextension_py(module, user=False, sys_prefix=False, overwrite=True build_labextension(base_path, logger=logger) full_dest = develop_labextension( - src, overwrite=overwrite, symlink=symlink, - user=user, sys_prefix=sys_prefix, labextensions_dir=labextensions_dir, - destination=dest, logger=logger - ) + src, + overwrite=overwrite, + symlink=symlink, + user=user, + sys_prefix=sys_prefix, + labextensions_dir=labextensions_dir, + destination=dest, + logger=logger, + ) full_dests.append(full_dest) return full_dests -def build_labextension(path, logger=None, development=False, static_url=None, source_map = False, core_path=None): +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') + core_path = osp.join(HERE, "staging") ext_path = osp.abspath(path) if logger: - logger.info('Building extension in %s' % path) + logger.info("Building extension in %s" % path) builder = _ensure_builder(ext_path, core_path) - arguments = ['node', builder, '--core-path', core_path, ext_path] + arguments = ["node", builder, "--core-path", core_path, ext_path] if static_url is not None: - arguments.extend(['--static-url', static_url]) + arguments.extend(["--static-url", static_url]) if development: - arguments.append('--development') + arguments.append("--development") if source_map: - arguments.append('--source-map') + arguments.append("--source-map") subprocess.check_call(arguments, cwd=ext_path) -def watch_labextension(path, labextensions_path, logger=None, development=False, source_map=False, core_path=None): +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') + core_path = osp.join(HERE, "staging") ext_path = osp.abspath(path) if logger: - logger.info('Building extension in %s' % path) + logger.info("Building extension in %s" % path) # Check to see if we need to create a symlink federated_extensions = get_federated_extensions(labextensions_path) - with open(pjoin(ext_path, 'package.json')) as fid: + with open(pjoin(ext_path, "package.json")) as fid: ext_data = json.load(fid) - if ext_data['name'] not in federated_extensions: + if ext_data["name"] not in federated_extensions: develop_labextension_py(ext_path, sys_prefix=True) else: - full_dest = pjoin(federated_extensions[ext_data['name']]['ext_dir'], ext_data['name']) - output_dir = pjoin(ext_path, ext_data['jupyterlab'].get('outputDir', 'static')) + full_dest = pjoin(federated_extensions[ext_data["name"]]["ext_dir"], ext_data["name"]) + output_dir = pjoin(ext_path, ext_data["jupyterlab"].get("outputDir", "static")) if not osp.islink(full_dest): shutil.rmtree(full_dest) os.symlink(output_dir, full_dest) builder = _ensure_builder(ext_path, core_path) - arguments = ['node', builder, '--core-path', core_path, '--watch', ext_path] + arguments = ["node", builder, "--core-path", core_path, "--watch", ext_path] if development: - arguments.append('--development') + arguments.append("--development") if source_map: - arguments.append('--source-map') + arguments.append("--source-map") subprocess.check_call(arguments, cwd=ext_path) -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # Private API -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ def _ensure_builder(ext_path, core_path): - """Ensure that we can build the extension and return the builder script path - """ + """Ensure that we can build the extension and return the builder script path""" # Test for compatible dependency on @jupyterlab/builder - with open(osp.join(core_path, 'package.json')) as fid: + with open(osp.join(core_path, "package.json")) as fid: core_data = json.load(fid) - with open(osp.join(ext_path, 'package.json')) as 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') + 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: - raise ValueError('Extensions require a devDependency on @jupyterlab/builder@%s' % depVersion1) + raise ValueError( + "Extensions require a devDependency on @jupyterlab/builder@%s" % depVersion1 + ) # 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') - overlap = _test_overlap(depVersion1, depVersion2, 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)) - if not osp.exists(osp.join(ext_path, 'node_modules')): - subprocess.check_call(['jlpm'], cwd=ext_path) + if "/" in depVersion2: + with open(osp.join(ext_path, depVersion2, "package.json")) as fid: + depVersion2 = json.load(fid).get("version") + if not osp.exists(osp.join(ext_path, "node_modules")): + subprocess.check_call(["jlpm"], cwd=ext_path) # 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')): + while not osp.exists(osp.join(target, "node_modules", "@jupyterlab", "builder")): if osp.dirname(target) == target: - raise ValueError('Could not find @jupyterlab/builder') + raise ValueError("Could not find @jupyterlab/builder") target = osp.dirname(target) - return osp.join(target, 'node_modules', '@jupyterlab', 'builder', 'lib', 'build-labextension.js') + overlap = _test_overlap(depVersion1, depVersion2, 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") + overlap = _test_overlap( + depVersion1, depVersion2, 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) + ) + + return osp.join( + target, "node_modules", "@jupyterlab", "builder", "lib", "build-labextension.js" + ) def _should_copy(src, dest, logger=None): @@ -281,7 +329,7 @@ def _should_copy(src, dest, logger=None): # 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) @@ -323,26 +371,28 @@ def _get_labextension_dir(user=False, sys_prefix=False, prefix=None, labextensio Get what you put in """ conflicting = [ - ('user', user), - ('prefix', prefix), - ('labextensions_dir', labextensions_dir), - ('sys_prefix', sys_prefix), + ("user", user), + ("prefix", prefix), + ("labextensions_dir", labextensions_dir), + ("sys_prefix", sys_prefix), ] - conflicting_set = ['{}={!r}'.format(n, v) for n, v in conflicting if v] + conflicting_set = ["{}={!r}".format(n, v) 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))) + "cannot specify more than one of user, sys_prefix, prefix, or labextensions_dir, but got: {}".format( + ", ".join(conflicting_set) + ) + ) if user: - labext = pjoin(jupyter_data_dir(), u'labextensions') + labext = pjoin(jupyter_data_dir(), "labextensions") elif sys_prefix: - labext = pjoin(ENV_JUPYTER_PATH[0], u'labextensions') + labext = pjoin(ENV_JUPYTER_PATH[0], "labextensions") elif prefix: - labext = pjoin(prefix, 'share', 'jupyter', 'labextensions') + labext = pjoin(prefix, "share", "jupyter", "labextensions") elif labextensions_dir: labext = labextensions_dir else: - labext = pjoin(SYSTEM_JUPYTER_PATH[0], 'labextensions') + labext = pjoin(SYSTEM_JUPYTER_PATH[0], "labextensions") return labext @@ -363,47 +413,66 @@ 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)) + raise FileNotFoundError("The path `{}` does not exist.".format(mod_path)) errors = [] # Check if the path is a valid labextension try: m = importlib.import_module(module) - if hasattr(m, '_jupyter_labextension_paths') : + if hasattr(m, "_jupyter_labextension_paths"): return m, m._jupyter_labextension_paths() except Exception as exc: errors.append(exc) + # Try to get the package name + package = None + + # Try getting the package name from pyproject.toml + if os.path.exists(os.path.join(mod_path, "pyproject.toml")): + with open(os.path.join(mod_path, "pyproject.toml"), "rb") as fid: + data = load(fid) + package = data.get("project", {}).get("name") + # Try getting the package name from setup.py - try: - package = subprocess.check_output([sys.executable, 'setup.py', '--name'], cwd=mod_path).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)) + if not package: + try: + package = ( + subprocess.check_output([sys.executable, "setup.py", "--name"], cwd=mod_path) + .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) + ) # 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]) sys.path.insert(0, mod_path) - from setuptools import find_packages, find_namespace_packages + from setuptools import find_namespace_packages, find_packages package_candidates = [ - package.replace('-', '_'), # Module with the same name as package + package.replace("-", "_"), # Module with the same name as package ] package_candidates.extend(find_packages(mod_path)) # Packages in the module path - package_candidates.extend(find_namespace_packages(mod_path)) # Namespace packages in the module path + package_candidates.extend( + find_namespace_packages(mod_path) + ) # Namespace packages in the module path for package in package_candidates: try: m = importlib.import_module(package) - if hasattr(m, '_jupyter_labextension_paths'): + if hasattr(m, "_jupyter_labextension_paths"): return m, m._jupyter_labextension_paths() except Exception as exc: errors.append(exc) - raise ModuleNotFoundError('There is no labextension at {}. Errors encountered: {}'.format(module, errors)) + raise ModuleNotFoundError( + "There is no labextension at {}. Errors encountered: {}".format(module, errors) + ) diff --git a/jupyterlab/handlers/__init__.py b/jupyterlab/handlers/__init__.py index e69de29..c146300 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/build_handler.py b/jupyterlab/handlers/build_handler.py index 89fdbf1..09553ae 100644 --- a/jupyterlab/handlers/build_handler.py +++ b/jupyterlab/handlers/build_handler.py @@ -2,8 +2,8 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from concurrent.futures import ThreadPoolExecutor import json +from concurrent.futures import ThreadPoolExecutor from threading import Event from jupyter_server.base.handlers import APIHandler @@ -11,8 +11,7 @@ from tornado import gen, web from tornado.concurrent import run_on_executor -from ..commands import build, clean, build_check, AppOptions, _ensure_options -from ..coreconfig import CoreConfig +from ..commands import AppOptions, _ensure_options, build, build_check, clean class Builder(object): @@ -34,32 +33,31 @@ 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(dict(status="stable", message="")) if self.building: - raise gen.Return(dict(status='building', message='')) + raise gen.Return(dict(status="building", message="")) try: messages = yield self._run_build_check( - self.app_dir, self.log, self.core_config, self.labextensions_path) - status = 'needed' if messages else 'stable' + self.app_dir, self.log, self.core_config, self.labextensions_path + ) + 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' - ) - status = 'stable' + self.log.info("Build is up to date") + 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(dict(status=status, message="\n".join(messages))) @gen.coroutine def build(self): if self._canceling: - raise ValueError('Cancel in progress') + raise ValueError("Cancel in progress") if not self.building: self.canceled = False self._future = future = gen.Future() @@ -67,10 +65,11 @@ def build(self): self._kill_event = evt = Event() try: yield self._run_build( - self.app_dir, self.log, evt, self.core_config, self.labextensions_path) + self.app_dir, self.log, evt, self.core_config, self.labextensions_path + ) future.set_result(True) except Exception as e: - if str(e) == 'Aborted': + if str(e) == "Aborted": future.set_result(False) else: future.set_exception(e) @@ -84,7 +83,7 @@ def build(self): @gen.coroutine def cancel(self): if not self.building: - raise ValueError('No current build') + raise ValueError("No current build") self._canceling = True yield self._future self._canceling = False @@ -92,26 +91,35 @@ def cancel(self): @run_on_executor def _run_build_check(self, app_dir, logger, core_config, labextensions_path): - return build_check(app_options=AppOptions( - app_dir=app_dir, logger=logger, core_config=core_config, labextensions_path=labextensions_path)) + return build_check( + app_options=AppOptions( + app_dir=app_dir, + logger=logger, + core_config=core_config, + labextensions_path=labextensions_path, + ) + ) @run_on_executor def _run_build(self, app_dir, logger, kill_event, core_config, labextensions_path): app_options = AppOptions( - app_dir=app_dir, logger=logger, kill_event=kill_event, - core_config=core_config, labextensions_path=labextensions_path) + app_dir=app_dir, + logger=logger, + kill_event=kill_event, + core_config=core_config, + labextensions_path=labextensions_path, + ) 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) self.builder = builder @@ -125,7 +133,7 @@ def get(self): @web.authenticated @gen.coroutine def delete(self): - self.log.warning('Canceling build') + self.log.warning("Canceling build") try: yield self.builder.cancel() except Exception as e: @@ -135,16 +143,16 @@ def delete(self): @web.authenticated @gen.coroutine def post(self): - self.log.debug('Starting build') + self.log.debug("Starting build") try: yield self.builder.build() except Exception as e: raise web.HTTPError(500, str(e)) if self.builder.canceled: - raise web.HTTPError(400, 'Build canceled') + raise web.HTTPError(400, "Build canceled") - self.log.debug('Build succeeded') + self.log.debug("Build succeeded") self.set_status(200) diff --git a/jupyterlab/handlers/error_handler.py b/jupyterlab/handlers/error_handler.py index 20e6976..43f1dc3 100644 --- a/jupyterlab/handlers/error_handler.py +++ b/jupyterlab/handlers/error_handler.py @@ -4,10 +4,9 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from tornado import web -from jupyterlab_server.server import JupyterHandler from jupyter_server.extension.handler import ExtensionHandlerMixin - +from jupyterlab_server.server import JupyterHandler +from tornado import web TEMPLATE = """ @@ -22,8 +21,8 @@ """ -class ErrorHandler(ExtensionHandlerMixin, JupyterHandler): +class ErrorHandler(ExtensionHandlerMixin, JupyterHandler): def initialize(self, messages=None, name=None): super(ErrorHandler, self).initialize(name=name) self.messages = messages @@ -31,5 +30,5 @@ def initialize(self, messages=None, name=None): @web.authenticated @web.removeslash def get(self): - msgs = ['

    %s

    ' % msg for msg in self.messages] - self.write(TEMPLATE % '\n'.join(msgs)) + msgs = ["

    %s

    " % msg for msg in self.messages] + self.write(TEMPLATE % "\n".join(msgs)) diff --git a/jupyterlab/handlers/extension_manager_handler.py b/jupyterlab/handlers/extension_manager_handler.py index 2257eb8..10b38e6 100644 --- a/jupyterlab/handlers/extension_manager_handler.py +++ b/jupyterlab/handlers/extension_manager_handler.py @@ -6,24 +6,38 @@ import json import os import re - from concurrent.futures import ThreadPoolExecutor from jupyter_server.base.handlers import APIHandler from jupyter_server.extension.handler import ExtensionHandlerMixin - from tornado import gen, web from ..commands import ( - get_app_info, install_extension, uninstall_extension, - enable_extension, disable_extension, read_package, - _AppHandler, get_latest_compatible_package_versions, - AppOptions, _ensure_options + _AppHandler, + _ensure_options, + disable_extension, + enable_extension, + get_app_info, + get_latest_compatible_package_versions, + install_extension, + read_package, + uninstall_extension, ) -def _make_extension_entry(name, description, url, enabled, core, latest_version, - installed_version, status, pkg_type, installed=None, install=None): +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, @@ -34,38 +48,39 @@ def _make_extension_entry(name, description, url, enabled, core, latest_version, latest_version=latest_version, installed_version=installed_version, status=status, - pkg_type=pkg_type + pkg_type=pkg_type, ) if installed is not None: - ret['installed'] = installed + ret["installed"] = installed if install is not None: - ret['install'] = install + 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() + 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.*)'), + "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': []} + 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')) + status[key].append(match.group("name")) return status @@ -92,65 +107,71 @@ def list_extensions(self): extensions = [] # 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' - )) - - for name, data in info['extensions'].items(): - if name in info['shadowed_exts']: + 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", + ) + ) + + for name, data in info["extensions"].items(): + if name in info["shadowed_exts"]: continue - status = 'ok' + status = "ok" pkg_info = yield self._get_pkg_info(name, data) - if info['compat_errors'].get(name, None): - status = 'error' + 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' - )) - 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( + status = "warning" + extensions.append( + _make_extension_entry( name=name, - description=data.get('description', ''), - url=data.get('homepage', ''), - installed=False, - enabled=False, + description=pkg_info.get("description", ""), + url=data["url"], + enabled=(name not in info["disabled"]), core=False, - latest_version=data['version'], - installed_version=data['version'], - status='warning', - pkg_type='prebuilt' - )) + # 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", + ) + ) + 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", + ) + ) raise gen.Return(extensions) @gen.coroutine @@ -159,40 +180,55 @@ def install(self, extension): 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',)) + 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',)) + 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',)) + 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',)) + raise gen.Return( + dict( + status="ok", + ) + ) @gen.coroutine def _get_pkg_info(self, name, data): """Get information about a package""" - info = read_package(data['path']) + 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] + info["latest_version"] = outdated[name] else: # Fallback to indicating that current is latest - info['latest_version'] = info['version'] + info["latest_version"] = info["version"] raise gen.Return(info) @@ -217,19 +253,16 @@ def refresh_outdated(self): def _load_outdated(self): """Get the latest compatible version""" info = get_app_info(app_options=self.app_options) - names = tuple(info['extensions'].keys()) + names = tuple(info["extensions"].keys()) data = yield self.executor.submit( - get_latest_compatible_package_versions, - names, - app_options=self.app_options + 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') + 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)) @@ -238,7 +271,6 @@ def _get_scheduled_uninstall_info(self, name): class ExtensionHandler(ExtensionHandlerMixin, APIHandler): - def initialize(self, manager=None, name=None): super(ExtensionHandler, self).initialize(name=name) self.manager = manager @@ -247,7 +279,7 @@ def initialize(self, manager=None, name=None): @gen.coroutine def get(self): """GET query returns info on all installed extensions""" - if self.get_argument('refresh', False) == '1': + if self.get_argument("refresh", False) == "1": yield self.manager.refresh_outdated() extensions = yield self.manager.list_extensions() self.finish(json.dumps(extensions)) @@ -257,26 +289,25 @@ def get(self): def post(self): """POST query performs an action on a specific extension""" data = self.get_json_body() - cmd = data['cmd'] - name = data['extension_name'] - if (cmd not in ('install', 'uninstall', 'enable', 'disable') or - not name): + cmd = data["cmd"] + name = data["extension_name"] + 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, "Could not process instruction %r with extension name %r" % (cmd, name) + ) # 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': + if cmd == "install": ret_value = yield self.manager.install(name) - elif cmd == 'uninstall': + elif cmd == "uninstall": ret_value = yield self.manager.uninstall(name) - elif cmd == 'enable': + elif cmd == "enable": ret_value = yield self.manager.enable(name) - elif cmd == 'disable': + elif cmd == "disable": ret_value = yield self.manager.disable(name) except gen.Return as e: ret_value = e.value diff --git a/jupyterlab/handlers/yjs_echo_ws.py b/jupyterlab/handlers/yjs_echo_ws.py deleted file mode 100644 index e253747..0000000 --- a/jupyterlab/handlers/yjs_echo_ws.py +++ /dev/null @@ -1,130 +0,0 @@ -"""Echo WebSocket handler for real time collaboration with Yjs""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import uuid -import time - -from tornado.ioloop import IOLoop -from jupyter_server.base.handlers import JupyterHandler -from tornado import web -from tornado.websocket import WebSocketHandler -from enum import IntEnum - -## The y-protocol defines messages types that just need to be propagated to all other peers. -## Here, we define some additional messageTypes that the server can interpret. -## Messages that the server can't interpret should be broadcasted to all other clients. - -class ServerMessageType(IntEnum): - # The client is asking for a lock. Should return a lock-identifier if one is available. - ACQUIRE_LOCK = 127 - # The client is asking to release a lock to make it available to other users again. - RELEASE_LOCK = 126 - # The client is asking to retrieve the initial state of the Yjs document. Return an empty buffer when nothing is available. - REQUEST_INITIALIZED_CONTENT = 125 - # The client retrieved an empty "initial content" and generated the initial state of the document after acquiring a lock. Store this. - PUT_INITIALIZED_CONTENT = 124 - # The client moved the document to a different location. After receiving this message, we make the current document available under a different url. - # The other clients are automatically notified of this change because the path is shared through the Yjs document as well. - RENAME_SESSION = 123 - -class YjsRoom: - def __init__(self): - self.lock = None - self.timeout = None - self.lock_holder = None - self.clients = {} - self.content = bytes([]) - - -class YjsEchoWebSocket(WebSocketHandler, JupyterHandler): - rooms = {} - - # Override max_message size to 1GB - @property - def max_message_size(self): - return 1024 * 1024 * 1024 - - async def get(self, *args, **kwargs): - if self.get_current_user() is None: - self.log.warning("Couldn't authenticate WebSocket connection") - raise web.HTTPError(403) - return await super().get(*args, **kwargs) - - def open(self, guid): - #print("[YJSEchoWS]: open", guid) - cls = self.__class__ - self.id = str(uuid.uuid4()) - self.room_id = guid - room = cls.rooms.get(self.room_id) - if room is None: - room = YjsRoom() - cls.rooms[self.room_id] = room - room.clients[self.id] = ( IOLoop.current(), self.hook_send_message, self ) - # Send SyncStep1 message (based on y-protocols) - self.write_message(bytes([0, 0, 1, 0]), binary=True) - - def on_message(self, message): - #print("[YJSEchoWS]: message, ", message) - cls = self.__class__ - room_id = self.room_id - room = cls.rooms.get(room_id) - if message[0] == ServerMessageType.ACQUIRE_LOCK: - now = int(time.time()) - if room.lock is None or now - room.timeout > (10 * len(room.clients)) : # no lock or timeout - room.lock = now - room.timeout = now - room.lock_holder = self.id - # print('Acquired new lock: ', room.lock) - # return acquired lock - self.write_message(bytes([ServerMessageType.ACQUIRE_LOCK]) + room.lock.to_bytes(4, byteorder = 'little'), binary=True) - - elif room.lock_holder == self.id : - # print('Update lock: ', room.timeout) - room.timeout = now - - elif message[0] == ServerMessageType.RELEASE_LOCK: - releasedLock = int.from_bytes(message[1:], byteorder = 'little') - # print("trying release lock: ", releasedLock) - if room.lock == releasedLock: - # print('released lock: ', room.lock) - room.lock = None - room.timeout = None - room.lock_holder = None - elif message[0] == ServerMessageType.REQUEST_INITIALIZED_CONTENT: - # print("client requested initial content") - self.write_message(bytes([ServerMessageType.REQUEST_INITIALIZED_CONTENT]) + room.content, binary=True) - elif message[0] == ServerMessageType.PUT_INITIALIZED_CONTENT: - # print("client put initialized content") - room.content = message[1:] - elif message[0] == ServerMessageType.RENAME_SESSION: - # We move the room to a different entry and also change the room_id property of each connected client - new_room_id = message[1:].decode("utf-8") - for client_id, (loop, hook_send_message, client) in room.clients.items() : - client.room_id = new_room_id - cls.rooms.pop(room_id) - cls.rooms[new_room_id] = room - # print("renamed room to " + new_room_id + ". Old room name was " + room_id) - elif room: - for client_id, (loop, hook_send_message, client) in room.clients.items() : - if self.id != client_id : - loop.add_callback(hook_send_message, message) - - def on_close(self): - # print("[YJSEchoWS]: close") - cls = self.__class__ - room = cls.rooms.get(self.room_id) - room.clients.pop(self.id) - if len(room.clients) == 0 : - cls.rooms.pop(self.room_id) - # print("[YJSEchoWS]: close room " + self.room_id) - - return True - - def check_origin(self, origin): - #print("[YJSEchoWS]: check origin") - return True - - def hook_send_message(self, msg): - self.write_message(msg, binary=True) diff --git a/jupyterlab/jlpmapp.py b/jupyterlab/jlpmapp.py index ce378e1..8617c5b 100644 --- a/jupyterlab/jlpmapp.py +++ b/jupyterlab/jlpmapp.py @@ -1,15 +1,16 @@ # coding: utf-8 """A Jupyter-aware wrapper for the yarn package manager""" +import os + # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import sys -import os -from jupyterlab_server.process import which, subprocess +from jupyterlab_server.process import subprocess, which HERE = os.path.dirname(os.path.abspath(__file__)) -YARN_PATH = os.path.join(HERE, 'staging', 'yarn.js') +YARN_PATH = os.path.join(HERE, "staging", "yarn.js") def execvp(cmd, argv): @@ -22,9 +23,10 @@ def execvp(cmd, argv): (Python bug#9148). """ cmd = which(cmd) - if os.name == 'nt': + if os.name == "nt": import signal import sys + p = subprocess.Popen([cmd] + argv[1:]) # Don't raise KeyboardInterrupt in the parent process. # Set this after spawning, to avoid subprocess inheriting handler. @@ -36,8 +38,7 @@ def execvp(cmd, argv): def main(argv=None): - """Run node and return the result. - """ + """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 43cf1a1..df46ab9 100644 --- a/jupyterlab/labapp.py +++ b/jupyterlab/labapp.py @@ -6,38 +6,58 @@ import json import os -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 from jupyter_server.serverapp import flags from jupyter_server.utils import url_path_join as ujoin - -from jupyterlab_server import LabServerApp, LicensesApp, WorkspaceExportApp, WorkspaceImportApp, WorkspaceListApp -from nbclassic.shim import NBClassicConfigShimMixin -from traitlets import Bool, Instance, Unicode, default +from jupyter_server_ydoc.ydoc import JupyterSQLiteYStore +from jupyterlab_server import ( + LabServerApp, + LicensesApp, + WorkspaceExportApp, + WorkspaceImportApp, + WorkspaceListApp, +) +from notebook_shim.shim import NotebookConfigShimMixin +from traitlets import Bool, Instance, Int, Type, Unicode, default +from ypy_websocket.ystore import BaseYStore from ._version import __version__ from .commands import ( - DEV_DIR, HERE, AppOptions, build, clean, ensure_app, - ensure_core, ensure_dev, get_app_dir, get_app_version, - get_user_settings_dir, get_workspaces_dir, pjoin, watch, - watch_dev + DEV_DIR, + HERE, + AppOptions, + build, + clean, + ensure_app, + ensure_core, + ensure_dev, + get_app_dir, + get_app_version, + get_user_settings_dir, + get_workspaces_dir, + pjoin, + watch, + watch_dev, ) from .coreconfig import CoreConfig from .debuglog import DebugLogFileMixin 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.yjs_echo_ws import YjsEchoWebSocket +from .handlers.extension_manager_handler import ( + ExtensionHandler, + ExtensionManager, + extensions_handler_path, +) -DEV_NOTE = """You're running JupyterLab from source. -If you're working on the TypeScript sources of JupyterLab, try running +DEV_NOTE = """You're running ElixirNote from source. +If you're working on the TypeScript sources of ElixirNote, try running - jupyter lab --dev-mode --watch + elixir-lab --dev-mode --watch -to have the system incrementally watch and build JupyterLab for you, as you +to have the system incrementally watch and build ElixirNote for you, as you make changes. """ @@ -47,54 +67,51 @@ """ build_aliases = dict(base_aliases) -build_aliases['app-dir'] = 'LabBuildApp.app_dir' -build_aliases['name'] = 'LabBuildApp.name' -build_aliases['version'] = 'LabBuildApp.version' -build_aliases['dev-build'] = 'LabBuildApp.dev_build' -build_aliases['minimize'] = 'LabBuildApp.minimize' -build_aliases['debug-log-path'] = 'DebugLogFileMixin.debug_log_path' +build_aliases["app-dir"] = "LabBuildApp.app_dir" +build_aliases["name"] = "LabBuildApp.name" +build_aliases["version"] = "LabBuildApp.version" +build_aliases["dev-build"] = "LabBuildApp.dev_build" +build_aliases["minimize"] = "LabBuildApp.minimize" +build_aliases["debug-log-path"] = "DebugLogFileMixin.debug_log_path" 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.", ) -build_flags['no-minimize'] = ( - {'LabBuildApp': {'minimize': False}}, - "Do not minimize a production build." -) -build_flags['splice-source'] = ( - {'LabBuildApp': {'splice_source': True}}, - "Splice source packages into app directory." +build_flags["splice-source"] = ( + {"LabBuildApp": {"splice_source": True}}, + "Splice source packages into app directory.", ) version = __version__ app_version = get_app_version() if version != app_version: - version = '%s (dev), %s (app)' % (__version__, app_version) + version = "%s (dev), %s (app)" % (__version__, app_version) buildFailureMsg = """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. -If you are building via the `jupyter lab build` command, you can disable +If you are building via the `elixir-lab build` command, you can disable these options like so: -jupyter lab build --dev-build=False --minimize=False +elixir-lab build --dev-build=False --minimize=False -You can also disable these options for all JupyterLab builds by adding these -lines to a Jupyter config file named `jupyter_config.py`: +You can also disable these options for all ElixirNote builds by adding these +lines to a Elixir config file named `elixir_config.py`: c.LabBuildApp.minimize = False c.LabBuildApp.dev_build = False -If you don't already have a `jupyter_config.py` file, you can create one by -adding a blank file of that name to any of the Jupyter config directories. +If you don't already have a `elixir_config.py` file, you can create one by +adding a blank file of that name to any of the Elixir config directories. The config directories can be listed by running: -jupyter --paths +elixir --paths Explanation: @@ -106,19 +123,20 @@ build is used in all circumstances. - `minimize`: This option controls whether your JS bundle is minified -during the Webpack build, which helps to improve JupyterLab's overall +during the Webpack build, which helps to improve ElixirNote's overall performance. However, the minifier plugin used by Webpack is very memory intensive, so turning it off may help the build finish successfully in low-memory environments. """ + class LabBuildApp(JupyterApp, DebugLogFileMixin): version = version description = """ - Build the JupyterLab application + Build the ElixirNote application - The application is built in the JupyterLab app directory in `/staging`. - When the build is complete it is put in the JupyterLab app `/static` + The application is built in the ElixirNote app directory in `/staging`. + When the build is complete it is put in the ElixirNote app `/static` directory, where it is used to serve the application. """ aliases = build_aliases @@ -127,59 +145,74 @@ class LabBuildApp(JupyterApp, DebugLogFileMixin): # Not configurable! core_config = Instance(CoreConfig, allow_none=True) - app_dir = Unicode('', config=True, - help="The app directory to build in") + app_dir = Unicode("", config=True, help="The app directory to build in") - name = Unicode('JupyterLab', config=True, - help="The name of the built application") + name = Unicode("ElixirNote", config=True, help="The name of the built application") - version = Unicode('', config=True, - help="The version of the built application") + # version = Unicode("", config=True, help="The version of the built application") - dev_build = Bool(None, allow_none=True, config=True, - help="Whether to build in dev mode. Defaults to True (dev mode) if there are any locally linked extensions, else defaults to False (production mode).") + dev_build = Bool( + None, + allow_none=True, + config=True, + help="Whether to build in dev mode. Defaults to True (dev mode) if there are any locally linked extensions, " + "else defaults to False (production mode).", + ) - minimize = Bool(True, config=True, - help="Whether to minimize a production build (defaults to True).") + minimize = Bool( + True, config=True, help="Whether to minimize a production build (defaults to True)." + ) - pre_clean = Bool(False, config=True, - help="Whether to clean before building (defaults to False)") + pre_clean = Bool( + False, config=True, help="Whether to clean before building (defaults to False)" + ) - splice_source = Bool(False, config=True, - help="Splice source packages into app directory.") + splice_source = Bool(False, config=True, help="Splice source packages into app directory.") def start(self): app_dir = self.app_dir or get_app_dir() app_options = AppOptions( - app_dir=app_dir, logger=self.log, core_config=self.core_config, splice_source=self.splice_source + app_dir=app_dir, + logger=self.log, + core_config=self.core_config, + splice_source=self.splice_source, ) - self.log.info('JupyterLab %s', version) + self.log.info("ElixirNote %s", version) with self.debug_logging(): if self.pre_clean: - self.log.info('Cleaning %s' % app_dir) + self.log.info("Cleaning %s" % app_dir) clean(app_options=app_options) - self.log.info('Building in %s', app_dir) + self.log.info("Building in %s", app_dir) try: production = None if self.dev_build is None else not self.dev_build - build(name=self.name, version=self.version, - app_options=app_options, production = production, minimize=self.minimize) + build( + name=self.name, + version=self.version, + app_options=app_options, + production=production, + minimize=self.minimize, + ) except Exception as e: print(buildFailureMsg) raise e clean_aliases = dict(base_aliases) -clean_aliases['app-dir'] = 'LabCleanApp.app_dir' +clean_aliases["app-dir"] = "LabCleanApp.app_dir" ext_warn_msg = "WARNING: this will delete all of your extensions, which will need to be reinstalled" clean_flags = dict(base_flags) -clean_flags['extensions'] = ({'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['all'] = ({'LabCleanApp': {'all': True}}, - 'Delete the entire contents of the app directory.\n%s' % ext_warn_msg) +clean_flags["extensions"] = ( + {"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["all"] = ( + {"LabCleanApp": {"all": True}}, + "Delete the entire contents of the app directory.\n%s" % ext_warn_msg, +) class LabCleanAppOptions(AppOptions): @@ -193,7 +226,7 @@ class LabCleanAppOptions(AppOptions): class LabCleanApp(JupyterApp): version = version description = """ - Clean the JupyterLab application + Clean the ElixirNote application This will clean the app directory by removing the `staging` directories. Optionally, the `extensions`, `settings`, and/or `static` directories, @@ -205,17 +238,21 @@ class LabCleanApp(JupyterApp): # Not configurable! core_config = Instance(CoreConfig, allow_none=True) - app_dir = Unicode('', config=True, help='The app directory to clean') + app_dir = Unicode("", config=True, help="The app directory to clean") - extensions = Bool(False, config=True, - help="Also delete /extensions.\n%s" % ext_warn_msg) + extensions = Bool( + False, config=True, help="Also delete /extensions.\n%s" % ext_warn_msg + ) settings = Bool(False, config=True, help="Also delete /settings") static = Bool(False, config=True, help="Also delete /static") - all = Bool(False, config=True, - help="Delete the entire contents of the app directory.\n%s" % ext_warn_msg) + all = Bool( + False, + config=True, + help="Delete the entire contents of the app directory.\n%s" % ext_warn_msg, + ) def start(self): app_options = LabCleanAppOptions( @@ -225,7 +262,7 @@ def start(self): extensions=self.extensions, settings=self.settings, static=self.static, - all=self.all + all=self.all, ) clean(app_options=app_options) @@ -233,7 +270,7 @@ def start(self): class LabPathApp(JupyterApp): version = version description = """ - Print the configured paths for the JupyterLab application + Print the configured paths for the ElixirNote application The application path can be configured using the JUPYTERLAB_DIR environment variable. @@ -244,16 +281,17 @@ class LabPathApp(JupyterApp): environment variable or it will fall back to '/lab/workspaces' in the default Jupyter configuration directory. """ + def start(self): - print('Application directory: %s' % get_app_dir()) - print('User Settings directory: %s' % get_user_settings_dir()) - print('Workspaces directory: %s' % get_workspaces_dir()) + print("Application directory: %s" % get_app_dir()) + print("User Settings directory: %s" % get_user_settings_dir()) + print("Workspaces directory: %s" % get_workspaces_dir()) class LabWorkspaceExportApp(WorkspaceExportApp): version = version - @default('workspaces_dir') + @default("workspaces_dir") def _default_workspaces_dir(self): return get_workspaces_dir() @@ -261,7 +299,7 @@ def _default_workspaces_dir(self): class LabWorkspaceImportApp(WorkspaceImportApp): version = version - @default('workspaces_dir') + @default("workspaces_dir") def _default_workspaces_dir(self): return get_workspaces_dir() @@ -269,7 +307,7 @@ def _default_workspaces_dir(self): class LabWorkspaceListApp(WorkspaceListApp): version = version - @default('workspaces_dir') + @default("workspaces_dir") def _default_workspaces_dir(self): return get_workspaces_dir() @@ -277,12 +315,12 @@ def _default_workspaces_dir(self): class LabWorkspaceApp(JupyterApp): version = version description = """ - Import or export a JupyterLab workspace or list all the JupyterLab workspaces + Import or export a ElixirNote workspace or list all the ElixirNote workspaces 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], @@ -313,15 +351,13 @@ class LabLicensesApp(LicensesApp): False, config=True, help="""Whether to start the app in dev mode. Uses the unpublished local - JavaScript packages in the `dev_mode` folder. In this case JupyterLab will - show a red stripe at the top of the page. It can only be used if JupyterLab + JavaScript packages in the `dev_mode` folder. In this case ElixirNote will + show a red stripe at the top of the page. It can only be used if ElixirNote is installed as `pip install -e .`. """, ) - app_dir = Unicode( - "", config=True, help="The app directory for which to show licenses" - ) + app_dir = Unicode("", config=True, help="The app directory for which to show licenses") aliases = { **LicensesApp.aliases, @@ -336,30 +372,32 @@ class LabLicensesApp(LicensesApp): ), } - @default('app_dir') + @default("app_dir") def _default_app_dir(self): return get_app_dir() - @default('static_dir') + @default("static_dir") def _default_static_dir(self): - return pjoin(self.app_dir, 'static') + return pjoin(self.app_dir, "static") aliases = dict(base_aliases) -aliases.update({ - 'ip': 'ServerApp.ip', - 'port': 'ServerApp.port', - 'port-retries': 'ServerApp.port_retries', - 'keyfile': 'ServerApp.keyfile', - 'certfile': 'ServerApp.certfile', - 'client-ca': 'ServerApp.client_ca', - 'notebook-dir': 'ServerApp.root_dir', - 'browser': 'ServerApp.browser', - 'pylab': 'ServerApp.pylab', -}) - - -class LabApp(NBClassicConfigShimMixin, LabServerApp): +aliases.update( + { + "ip": "ServerApp.ip", + "port": "ServerApp.port", + "port-retries": "ServerApp.port_retries", + "keyfile": "ServerApp.keyfile", + "certfile": "ServerApp.certfile", + "client-ca": "ServerApp.client_ca", + "notebook-dir": "ServerApp.root_dir", + "browser": "ServerApp.browser", + "pylab": "ServerApp.pylab", + } +) + + +class LabApp(NotebookConfigShimMixin, LabServerApp): version = version name = "lab" @@ -369,73 +407,65 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): load_other_extensions = True description = """ - JupyterLab - An extensible computational environment for Jupyter. + ElixirNote - An extensible computational environment for Jupyter. This launches a Tornado based HTML Server that serves up an - HTML5/Javascript JupyterLab client. + HTML5/Javascript ElixirNote client. - JupyterLab has three different modes of running: + ElixirNote has three different modes of running: - * Core mode (`--core-mode`): in this mode JupyterLab will run using the JavaScript - assets contained in the installed `jupyterlab` Python package. In core mode, no - extensions are enabled. This is the default in a stable JupyterLab release if you + * Core mode (`--core-mode`): in this mode ElixirNote will run using the JavaScript + assets contained in the installed `ElixirNote` Python package. In core mode, no + extensions are enabled. This is the default in a stable ElixirNote release if you have no extensions installed. * Dev mode (`--dev-mode`): uses the unpublished local JavaScript packages in the - `dev_mode` folder. In this case JupyterLab will show a red stripe at the top of - the page. It can only be used if JupyterLab is installed as `pip install -e .`. - * App mode: JupyterLab allows multiple JupyterLab "applications" to be + `dev_mode` folder. In this case ElixirNote will show a red stripe at the top of + the page. It can only be used if ElixirNote is installed as `pip install -e .`. + * App mode: ElixirNote allows multiple ElixirNote "applications" to be created by the user with different combinations of extensions. The `--app-dir` can be used to set a directory for different applications. The default application path can be found using `jupyter lab path`. """ examples = """ - jupyter lab # start JupyterLab - jupyter lab --dev-mode # start JupyterLab in development mode, with no extensions - jupyter lab --core-mode # start JupyterLab in core mode, with no extensions - jupyter lab --app-dir=~/myjupyterlabapp # start JupyterLab with a particular set of extensions - jupyter lab --certfile=mycert.pem # use SSL/TLS certificate + elixir-lab # start ElixirNote + elixir-lab --dev-mode # start ElixirNote in development mode, with no extensions + elixir-lab --core-mode # start ElixirNote in core mode, with no extensions + elixir-lab --app-dir=~/myElixirNoteApp # start ElixirNote with a particular set of extensions + elixir-lab --certfile=mycert.pem # use SSL/TLS certificate """ aliases = aliases - aliases.update({ - 'watch': 'LabApp.watch', - }) - aliases['app-dir'] = 'LabApp.app_dir' + aliases.update( + { + "watch": "LabApp.watch", + } + ) + aliases["app-dir"] = "LabApp.app_dir" flags = flags - 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["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['watch'] = ( - {'LabApp': {'watch': True}}, - "Start the app in watch mode." + flags["watch"] = ({"LabApp": {"watch": True}}, "Start the app in watch mode.") + flags["splice-source"] = ( + {"LabApp": {"splice_source": True}}, + "Splice source packages into app directory.", ) - flags['splice-source'] = ( - {'LabApp': {'splice_source': True}}, - "Splice source packages into app directory." + flags["expose-app-in-browser"] = ( + {"LabApp": {"expose_app_in_browser": True}}, + """Expose the global app instance to browser via window.elixirnote. + It is also available via the deprecated window.elixirnote name.""", ) - 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.""" + flags["extensions-in-dev-mode"] = ( + {"LabApp": {"extensions_in_dev_mode": True}}, + "Load prebuilt extensions in dev-mode.", ) - flags['extensions-in-dev-mode'] = ( - {'LabApp': {'extensions_in_dev_mode': True}}, - "Load prebuilt extensions in dev-mode." - ) - flags['collaborative'] = ( - {'LabApp': {'collaborative': True}}, - "Whether to enable collaborative mode (experimental)." - ) - flags['mirror-sync'] = ( - {'LabApp': {'mirror_sync': True}}, - "Sync notebook dir to minio buckets (experimental)." + flags["collaborative"] = ( + {"LabApp": {"collaborative": True}}, + "Whether to enable collaborative mode.", ) subcommands = dict( @@ -445,148 +475,178 @@ class LabApp(NBClassicConfigShimMixin, LabServerApp): paths=(LabPathApp, LabPathApp.description.splitlines()[0]), workspace=(LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), workspaces=(LabWorkspaceApp, LabWorkspaceApp.description.splitlines()[0]), - licenses=(LabLicensesApp, LabLicensesApp.description.splitlines()[0]) + licenses=(LabLicensesApp, LabLicensesApp.description.splitlines()[0]), ) - default_url = Unicode('/doc', config=True, - help="The default URL to redirect to from `/`") + default_url = Unicode("/doc", config=True, help="The default URL to redirect to from `/`") - override_static_url = Unicode(config=True, help=('The override url for static lab assets, typically a CDN.')) + override_static_url = Unicode( + config=True, help=("The override url for static lab assets, typically a CDN.") + ) - override_theme_url = Unicode(config=True, help=('The override url for static lab theme assets, typically a CDN.')) + override_theme_url = Unicode( + 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.") + app_dir = Unicode(None, config=True, help="The app directory to launch ElixirNote from.") - user_settings_dir = Unicode(get_user_settings_dir(), config=True, - help="The directory for user settings.") + user_settings_dir = Unicode( + get_user_settings_dir(), config=True, help="The directory for user settings." + ) - workspaces_dir = Unicode(get_workspaces_dir(), config=True, - help="The directory for workspaces") + workspaces_dir = Unicode(get_workspaces_dir(), config=True, help="The directory for workspaces") - core_mode = Bool(False, config=True, - help="""Whether to start the app in core mode. In this mode, JupyterLab + core_mode = Bool( + False, + config=True, + help="""Whether to start the app in core mode. In this mode, ElixirNote will run using the JavaScript assets that are within the installed - JupyterLab Python package. In core mode, third party extensions are disabled. + ElixirNote Python package. In core mode, third party extensions are disabled. The `--dev-mode` flag is an alias to this to be used when the Python package itself is installed in development mode (`pip install -e .`). - """) + """, + ) - dev_mode = Bool(False, config=True, + dev_mode = Bool( + False, + config=True, help="""Whether to start the app in dev mode. Uses the unpublished local - JavaScript packages in the `dev_mode` folder. In this case JupyterLab will - show a red stripe at the top of the page. It can only be used if JupyterLab + JavaScript packages in the `dev_mode` folder. In this case ElixirNote will + show a red stripe at the top of the page. It can only be used if ElixirNote is installed as `pip install -e .`. - """) + """, + ) - extensions_in_dev_mode = Bool(False, config=True, + extensions_in_dev_mode = Bool( + False, + config=True, help="""Whether to load prebuilt extensions in dev mode. This may be useful to run and test prebuilt extensions in development installs of - JupyterLab. APIs in a JupyterLab development install may be + ElixirNote. APIs in a ElixirNote development install may be incompatible with published packages, so prebuilt extensions compiled - against published packages may not work correctly.""") + against published packages may not work correctly.""", + ) - watch = Bool(False, config=True, - help="Whether to serve the app in watch mode") + watch = Bool(False, config=True, help="Whether to serve the app in watch mode") - splice_source = Bool(False, config=True, - help="Splice source packages into app directory.") + 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") + expose_app_in_browser = Bool( + False, + config=True, + help="Whether to expose the global app instance to browser via window.elixirnote", + ) + + collaborative = Bool(True, config=True, help="Whether to enable collaborative mode.") - collaborative = Bool(False, config=True, - help="Whether to enable collaborative mode (experimental).") + collaborative_file_poll_interval = Int( + 1, + config=True, + help="""The period in seconds to check for file changes in the back-end (relevant only + in collaborative mode). Defaults to 1s, if 0 then file changes will only be checked when + saving changes from the front-end.""", + ) - mirror_sync = Bool(False, config=True, help="Sync notebook dir to minio buckets (experimental).") + collaborative_document_cleanup_delay = Int( + 60, + allow_none=True, + config=True, + help="""The delay in seconds to keep a document in memory in the back-end after all clients + disconnect (relevant only in collaborative mode). Defaults to 60s, if None then the + document will be kept in memory forever.""", + ) - @default('app_dir') + collaborative_ystore_class = Type( + default_value=JupyterSQLiteYStore, + klass=BaseYStore, + config=True, + help="""The YStore class to use for storing Y updates (relevant only in collaborative mode). + Defaults to JupyterSQLiteYStore, which stores Y updates in a '.jupyter_ystore.db' SQLite + database in the current directory.""", + ) + + @default("app_dir") def _default_app_dir(self): - # app_dir = get_app_dir() - # if self.core_mode: - # app_dir = HERE - # elif self.dev_mode: - # app_dir = DEV_DIR - # return app_dir - return DEV_DIR - - @default('app_settings_dir') + app_dir = get_app_dir() + if self.core_mode: + app_dir = HERE + elif self.dev_mode: + app_dir = DEV_DIR + self.log.info("Default app dir: {}".format(app_dir)) + return app_dir + + @default("app_settings_dir") def _default_app_settings_dir(self): - return pjoin(self.app_dir, 'settings') + return pjoin(self.app_dir, "settings") - @default('app_version') + @default("app_version") def _default_app_version(self): return app_version - @default('cache_files') + @default("cache_files") def _default_cache_files(self): return False - @default('schemas_dir') + @default("schemas_dir") def _default_schemas_dir(self): - return pjoin(self.app_dir, 'schemas') + return pjoin(self.app_dir, "schemas") - @default('templates_dir') + @default("templates_dir") def _default_templates_dir(self): - return pjoin(self.app_dir, 'static') + return pjoin(self.app_dir, "static") - @default('themes_dir') + @default("themes_dir") def _default_themes_dir(self): if self.override_theme_url: - return '' - return pjoin(self.app_dir, 'themes') + return "" + return pjoin(self.app_dir, "themes") - @default('static_dir') + @default("static_dir") def _default_static_dir(self): - return pjoin(self.app_dir, 'static') + return pjoin(self.app_dir, "static") - @default('static_url_prefix') + @default("static_url_prefix") 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 = "/static/{name}/".format(name=self.name) return ujoin(self.serverapp.base_url, static_url) - @default('theme_url') + @default("theme_url") def _default_theme_url(https://github.com/self): if self.override_theme_url: return self.override_theme_url - return '' + return "" def initialize_templates(self): - # Force set `dev_mode = True` - self.dev_mode = True - # Determine which model to run JupyterLab + # Determine which model to run ElixirNote if self.core_mode or self.app_dir.startswith(HERE + os.sep): self.core_mode = True - self.log.info('Running JupyterLab in core mode') + self.log.info("Running ElixirNote in core mode") if self.dev_mode or self.app_dir.startswith(DEV_DIR + os.sep): self.dev_mode = True - self.log.info('Running JupyterLab in dev mode') + self.log.info("Running ElixirNote 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. + # Set the paths based on ElixirNote's mode. if self.dev_mode: - dev_static_dir = ujoin(DEV_DIR, 'static') + dev_static_dir = ujoin(DEV_DIR, "static") self.static_paths = [dev_static_dir] self.template_paths = [dev_static_dir] - self.log.info('Static paths: {}'.format(self.static_paths)) - self.log.info('Template paths: {}'.format(self.template_paths)) if not self.extensions_in_dev_mode: self.labextensions_path = [] self.extra_labextensions_path = [] elif self.core_mode: - dev_static_dir = ujoin(HERE, 'static') + dev_static_dir = ujoin(HERE, "static") self.static_paths = [dev_static_dir] self.template_paths = [dev_static_dir] self.labextensions_path = [] @@ -595,41 +655,37 @@ 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): handlers = [] - # Set config for Jupyterlab - page_config = self.serverapp.web_app.settings.setdefault('page_config_data', {}) - page_config.setdefault('buildAvailable', not self.core_mode and not self.dev_mode) - page_config.setdefault('buildCheck', not self.core_mode and not self.dev_mode) - page_config['devMode'] = self.dev_mode - 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 + # Set config for ElixirNote + page_config = self.serverapp.web_app.settings.setdefault("page_config_data", {}) + page_config.setdefault("buildAvailable", not self.core_mode and not self.dev_mode) + page_config.setdefault("buildCheck", not self.core_mode and not self.dev_mode) + page_config["devMode"] = self.dev_mode + 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 # Client-side code assumes notebookVersion is a JSON-encoded string - page_config['notebookVersion'] = json.dumps(jpserver_version_info) + page_config["notebookVersion"] = json.dumps(jpserver_version_info) - self.log.info('JupyterLab extension loaded from %s' % HERE) - self.log.info('JupyterLab application directory is %s' % self.app_dir) + self.log.info("ElixirNote extension loaded from %s" % HERE) + self.log.info("ElixirNote application directory is %s" % self.app_dir) - build_handler_options = AppOptions(logger=self.log, app_dir=self.app_dir, labextensions_path = self.extra_labextensions_path + self.labextensions_path, splice_source=self.splice_source) + build_handler_options = AppOptions( + logger=self.log, + app_dir=self.app_dir, + labextensions_path=self.extra_labextensions_path + self.labextensions_path, + splice_source=self.splice_source, + ) builder = Builder(self.core_mode, app_options=build_handler_options) - build_handler = (build_path, BuildHandler, {'builder': builder}) + build_handler = (build_path, BuildHandler, {"builder": builder}) handlers.append(build_handler) - # Yjs Echo WebSocket handler - yjs_echo_handler = (r"/api/yjs/(.*)", YjsEchoWebSocket) - handlers.append(yjs_echo_handler) - errored = False if self.core_mode: @@ -645,57 +701,51 @@ def initialize_handlers(self): msgs = ensure_app(self.app_dir) if msgs: [self.log.error(msg) for msg in msgs] - handler = (self.app_url, ErrorHandler, { 'messages': msgs }) + handler = (self.app_url, ErrorHandler, {"messages": msgs}) handlers.append(handler) errored = True if self.watch: - self.log.info('Starting JupyterLab watch mode...') + self.log.info("Starting ElixirNote watch mode...") if self.dev_mode: watch_dev(self.log) else: watch(app_options=build_handler_options) - page_config['buildAvailable'] = False + page_config["buildAvailable"] = False 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} - ) + ext_handler = (extensions_handler_path, ExtensionHandler, {"manager": ext_manager}) handlers.append(ext_handler) # If running under JupyterHub, add more metadata. - if 'hub_prefix' in self.serverapp.tornado_settings: + if "hub_prefix" in self.serverapp.tornado_settings: tornado_settings = self.serverapp.tornado_settings - hub_prefix = tornado_settings['hub_prefix'] - page_config['hubPrefix'] = hub_prefix - page_config['hubHost'] = tornado_settings['hub_host'] - page_config['hubUser'] = tornado_settings['user'] - page_config['shareUrl'] = ujoin(hub_prefix, 'user-redirect') + hub_prefix = tornado_settings["hub_prefix"] + page_config["hubPrefix"] = hub_prefix + page_config["hubHost"] = tornado_settings["hub_host"] + page_config["hubUser"] = tornado_settings["user"] + page_config["shareUrl"] = ujoin(hub_prefix, "user-redirect") # Assume the server_name property indicates running JupyterHub 1.0. - if hasattr(self.serverapp, 'server_name'): - page_config['hubServerName'] = self.serverapp.server_name - api_token = os.getenv('JUPYTERHUB_API_TOKEN', '') - page_config['token'] = api_token - - if self.mirror_sync: - # Only idg-notebook image can take effect - source_dir = "/data/notebooks/default" - target_dir = "myminio/notebooks/{}/default".format(page_config['hubUser']) - cmd = 'echo "*/2 * * * * root mc mirror {} {} --overwrite" >> /etc/crontab'.format(source_dir, target_dir) - print(cmd) - os.system(cmd) - os.system("service cron start") - self.log.info("Sync notebook dir to minio buckets") - - # Update Jupyter Server's webapp settings with jupyterlab settings. - self.serverapp.web_app.settings['page_config_data'] = page_config - # self.log.info('App settings: {}'.format(self.serverapp.web_app.settings)) - - # Extend Server handlers with jupyterlab handlers. + if hasattr(self.serverapp, "server_name"): + page_config["hubServerName"] = self.serverapp.server_name + api_token = os.getenv("JUPYTERHUB_API_TOKEN", "") + page_config["token"] = api_token + + self.log.info("App page config: {}".format(page_config)) + + # Update Jupyter Server's webapp settings with ElixirNote settings. + self.serverapp.web_app.settings.update( + { + "page_config_data": page_config, + "collaborative_file_poll_interval": self.collaborative_file_poll_interval, + "collaborative_document_cleanup_delay": self.collaborative_document_cleanup_delay, + "collaborative_ystore_class": self.collaborative_ystore_class, + } + ) + + # Extend Server handlers with ElixirNote handlers. self.handlers.extend(handlers) super().initialize_handlers() @@ -703,11 +753,12 @@ def initialize(self, argv=None): """Subclass because the ExtensionApp.initialize() method does not take arguments""" super().initialize() -#----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- # Main entry point -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- main = launch_new_instance = LabApp.launch_instance -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/jupyterlab/labextensions.py b/jupyterlab/labextensions.py index 0e5ca38..32b1152 100644 --- a/jupyterlab/labextensions.py +++ b/jupyterlab/labextensions.py @@ -15,78 +15,78 @@ from jupyterlab.debuglog import DebugLogFileMixin from .commands import ( - HERE, AppOptions, build, check_extension, - disable_extension, enable_extension, get_app_version, - install_extension, link_package, list_extensions, - uninstall_extension, unlink_package, update_extension + HERE, + AppOptions, + build, + check_extension, + disable_extension, + enable_extension, + get_app_version, + install_extension, + link_package, + list_extensions, + uninstall_extension, + 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) -flags['no-build'] = ( - {'BaseExtensionApp': {'should_build': False}}, - "Defer building the app after the action." -) -flags['dev-build'] = ( - {'BaseExtensionApp': {'dev_build': True}}, - "Build in development mode." +flags["no-build"] = ( + {"BaseExtensionApp": {"should_build": False}}, + "Defer building the app after the action.", ) -flags['no-minimize'] = ( - {'BaseExtensionApp': {'minimize': False}}, - "Do not minimize a production build." +flags["dev-build"] = ({"BaseExtensionApp": {"dev_build": True}}, "Build in development mode.") +flags["no-minimize"] = ( + {"BaseExtensionApp": {"minimize": False}}, + "Do not minimize a production build.", ) -flags['clean'] = ( - {'BaseExtensionApp': {'should_clean': True}}, - "Cleanup intermediate files after the action." +flags["clean"] = ( + {"BaseExtensionApp": {"should_clean": True}}, + "Cleanup intermediate files after the action.", ) -flags['splice-source'] = ( - {'BaseExtensionApp': {'splice_source': True}}, - "Splice source packages into app directory." +flags["splice-source"] = ( + {"BaseExtensionApp": {"splice_source": True}}, + "Splice source packages into app directory.", ) check_flags = copy(flags) -check_flags['installed'] = ( - {'CheckLabExtensionsApp': {'should_check_installed_only': True}}, - "Check only if the extension is installed." +check_flags["installed"] = ( + {"CheckLabExtensionsApp": {"should_check_installed_only": True}}, + "Check only if the extension is installed.", ) develop_flags = copy(flags) -develop_flags['overwrite'] = ( - {'DevelopLabExtensionApp': {'overwrite': True}}, - "Overwrite files" -) +develop_flags["overwrite"] = ({"DevelopLabExtensionApp": {"overwrite": True}}, "Overwrite files") update_flags = copy(flags) -update_flags['all'] = ( - {'UpdateLabExtensionApp': {'all': True}}, - "Update all extensions" -) +update_flags["all"] = ({"UpdateLabExtensionApp": {"all": True}}, "Update all extensions") uninstall_flags = copy(flags) -uninstall_flags['all'] = ( - {'UninstallLabExtensionApp': {'all': True}}, - "Uninstall all extensions" -) +uninstall_flags["all"] = ({"UninstallLabExtensionApp": {"all": True}}, "Uninstall all extensions") aliases = dict(base_aliases) -aliases['app-dir'] = 'BaseExtensionApp.app_dir' -aliases['dev-build'] = 'BaseExtensionApp.dev_build' -aliases['minimize'] = 'BaseExtensionApp.minimize' -aliases['debug-log-path'] = 'DebugLogFileMixin.debug_log_path' +aliases["app-dir"] = "BaseExtensionApp.app_dir" +aliases["dev-build"] = "BaseExtensionApp.dev_build" +aliases["minimize"] = "BaseExtensionApp.minimize" +aliases["debug-log-path"] = "DebugLogFileMixin.debug_log_path" install_aliases = copy(aliases) -install_aliases['pin-version-as'] = 'InstallLabExtensionApp.pin' +install_aliases["pin-version-as"] = "InstallLabExtensionApp.pin" enable_aliases = copy(aliases) -enable_aliases['level'] = 'EnableLabExtensionsApp.level' +enable_aliases["level"] = "EnableLabExtensionsApp.level" disable_aliases = copy(aliases) -disable_aliases['level'] = 'DisableLabExtensionsApp.level' +disable_aliases["level"] = "DisableLabExtensionsApp.level" VERSION = get_app_version() -HERE = os.path.abspath(os.path.dirname(__file__)) class BaseExtensionApp(JupyterApp, DebugLogFileMixin): version = VERSION @@ -97,48 +97,63 @@ class BaseExtensionApp(JupyterApp, DebugLogFileMixin): # Not configurable! core_config = Instance(CoreConfig, allow_none=True) - app_dir = Unicode('', config=True, - help="The app directory to target") + app_dir = Unicode("", config=True, help="The app directory to target") - should_build = Bool(True, config=True, - help="Whether to build the app after the action") + should_build = Bool(True, config=True, help="Whether to build the app after the action") - dev_build = Bool(None, allow_none=True, config=True, - help="Whether to build in dev mode. Defaults to True (dev mode) if there are any locally linked extensions, else defaults to False (production mode).") + dev_build = Bool( + None, + allow_none=True, + config=True, + help="Whether to build in dev mode. Defaults to True (dev mode) if there are any locally linked extensions, else defaults to False (production mode).", + ) - minimize = Bool(True, config=True, - help="Whether to minimize a production build (defaults to True).") + minimize = Bool( + True, config=True, help="Whether to minimize a production build (defaults to True)." + ) - should_clean = Bool(False, config=True, - help="Whether temporary files should be cleaned up after building jupyterlab") + should_clean = Bool( + False, + config=True, + help="Whether temporary files should be cleaned up after building jupyterlab", + ) - splice_source = Bool(False, config=True, - help="Splice source packages into app directory.") + splice_source = Bool(False, config=True, help="Splice source packages into app directory.") - labextensions_path = List(Unicode(), help='The standard paths to look in for prebuilt JupyterLab extensions') + labextensions_path = List( + Unicode(), help="The standard paths to look in for prebuilt JupyterLab extensions" + ) - @default('labextensions_path') + @default("labextensions_path") def _default_labextensions_path(self): lab = LabApp() lab.load_config_file() return lab.extra_labextensions_path + lab.labextensions_path - @default('splice_source') + @default("splice_source") def _default_splice_source(self): version = get_app_version(AppOptions(app_dir=self.app_dir)) - return version.endswith('-spliced') + return version.endswith("-spliced") def start(self): if self.app_dir and self.app_dir.startswith(HERE): - raise ValueError('Cannot run lab extension commands in core app') + raise ValueError("Cannot run lab extension commands in core app") with self.debug_logging(): ans = self.run_task() if ans and self.should_build: production = None if self.dev_build is None else not self.dev_build - app_options = AppOptions(app_dir=self.app_dir, logger=self.log, - core_config=self.core_config, splice_source=self.splice_source) - build(clean_staging=self.should_clean, - production = production, minimize = self.minimize, app_options=app_options) + app_options = AppOptions( + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + splice_source=self.splice_source, + ) + build( + clean_staging=self.should_clean, + production=production, + minimize=self.minimize, + app_options=app_options, + ) def run_task(self): pass @@ -165,30 +180,31 @@ class InstallLabExtensionApp(BaseExtensionApp): """ aliases = install_aliases - pin = Unicode('', config=True, - help="Pin this version with a certain alias") + pin = Unicode("", config=True, help="Pin this version with a certain alias") def run_task(self): - pinned_versions = self.pin.split(',') + 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 + 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) - ]) + 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") @@ -196,88 +212,112 @@ class DevelopLabExtensionApp(BaseExtensionApp): overwrite = Bool(False, config=True, help="Whether to overwrite files") symlink = Bool(True, config=False, help="Whether to use a symlink") - labextensions_dir = Unicode('', config=True, - help="Full path to labextensions dir (probably use prefix or user)") + labextensions_dir = Unicode( + "", config=True, help="Full path to labextensions dir (probably use prefix or user)" + ) def run_task(self): "Add config for this labextension" self.extra_args = self.extra_args or [os.getcwd()] for arg in self.extra_args: - develop_labextension_py(arg, user=self.user, sys_prefix=self.sys_prefix, labextensions_dir=self.labextensions_dir, logger=self.log, overwrite=self.overwrite, - symlink=self.symlink) + develop_labextension_py( + arg, + user=self.user, + sys_prefix=self.sys_prefix, + labextensions_dir=self.labextensions_dir, + logger=self.log, + overwrite=self.overwrite, + symlink=self.symlink, + ) class BuildLabExtensionApp(BaseExtensionApp): - description = "Build labextension" + description = "(developer) Build labextension" - static_url = Unicode('', config=True, - help="Sets the url for static assets when building") + static_url = Unicode("", config=True, help="Sets the url for static assets when building") - development = Bool(False, config=True, - help="Build in development mode") + development = Bool(False, config=True, help="Build in development mode") - source_map = Bool(False, config=True, - help="Generate source maps") + source_map = Bool(False, config=True, help="Generate source maps") - core_path = Unicode(os.path.join(HERE, 'staging'), config=True, - help="Directory containing core application package.json file") + core_path = Unicode( + os.path.join(HERE, "staging"), + config=True, + help="Directory containing core application package.json file", + ) aliases = { - 'static-url': 'BuildLabExtensionApp.static_url', - 'development': 'BuildLabExtensionApp.development', - 'source-map': 'BuildLabExtensionApp.source_map', - 'core-path': 'BuildLabExtensionApp.core_path' + "static-url": "BuildLabExtensionApp.static_url", + "development": "BuildLabExtensionApp.development", + "source-map": "BuildLabExtensionApp.source_map", + "core-path": "BuildLabExtensionApp.core_path", } def run_task(self): self.extra_args = self.extra_args or [os.getcwd()] - build_labextension(self.extra_args[0], logger=self.log, development=self.development, static_url=self.static_url or None, source_map = self.source_map, - core_path = self.core_path or None) + build_labextension( + self.extra_args[0], + logger=self.log, + development=self.development, + static_url=self.static_url or None, + source_map=self.source_map, + core_path=self.core_path or None, + ) class WatchLabExtensionApp(BaseExtensionApp): - description = "Watch labextension" + description = "(developer) Watch labextension" - development = Bool(True, config=True, - help="Build in development mode") + development = Bool(True, config=True, help="Build in development mode") - source_map = Bool(False, config=True, - help="Generate source maps") + source_map = Bool(False, config=True, help="Generate source maps") - core_path = Unicode(os.path.join(HERE, 'staging'), config=True, - help="Directory containing core application package.json file") + core_path = Unicode( + os.path.join(HERE, "staging"), + config=True, + help="Directory containing core application package.json file", + ) aliases = { - 'development': 'BuildLabExtensionApp.development', - 'source-map': 'BuildLabExtensionApp.source_map', - 'core-path': 'BuildLabExtensionApp.core_path' + "development": "BuildLabExtensionApp.development", + "source-map": "BuildLabExtensionApp.source_map", + "core-path": "BuildLabExtensionApp.core_path", } + def run_task(self): self.extra_args = self.extra_args or [os.getcwd()] labextensions_path = self.labextensions_path - watch_labextension(self.extra_args[0], labextensions_path, logger=self.log, development=self.development, source_map=self.source_map, - core_path = self.core_path or None) + watch_labextension( + self.extra_args[0], + labextensions_path, + logger=self.log, + development=self.development, + source_map=self.source_map, + core_path=self.core_path or None, + ) 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") def run_task(self): 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, logger=self.log, - core_config=self.core_config, labextensions_path=self.labextensions_path) + app_options = AppOptions( + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ) 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): @@ -288,21 +328,17 @@ class LinkLabExtensionApp(BaseExtensionApp): package is manually re-installed from its source location when `jupyter lab build` is run. """ - should_build = Bool(True, config=True, - help="Whether to build the app after the action") + should_build = Bool(True, config=True, help="Whether to build the app after the action") def run_task(self): self.extra_args = self.extra_args or [os.getcwd()] options = AppOptions( - app_dir=self.app_dir, logger=self.log, + app_dir=self.app_dir, + logger=self.log, labextensions_path=self.labextensions_path, - core_config=self.core_config) - return any([ - link_package( - arg, - app_options=options) - for arg in self.extra_args - ]) + core_config=self.core_config, + ) + return any([link_package(arg, app_options=options) for arg in self.extra_args]) class UnlinkLabExtensionApp(BaseExtensionApp): @@ -311,117 +347,138 @@ class UnlinkLabExtensionApp(BaseExtensionApp): def run_task(self): self.extra_args = self.extra_args or [os.getcwd()] options = AppOptions( - app_dir=self.app_dir, logger=self.log, + app_dir=self.app_dir, + logger=self.log, labextensions_path=self.labextensions_path, - core_config=self.core_config) - return any([ - unlink_package( - arg, - app_options=options) - for arg in self.extra_args - ]) + core_config=self.core_config, + ) + 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") def run_task(self): self.extra_args = self.extra_args or [os.getcwd()] options = AppOptions( - app_dir=self.app_dir, logger=self.log, + app_dir=self.app_dir, + logger=self.log, labextensions_path=self.labextensions_path, - core_config=self.core_config) - return any([ - uninstall_extension( - arg, all_=self.all, - app_options=options) - for arg in self.extra_args - ]) + core_config=self.core_config, + ) + return any( + [ + uninstall_extension(arg, all_=self.all, app_options=options) + for arg in self.extra_args + ] + ) class ListLabExtensionsApp(BaseExtensionApp): description = "List the installed labextensions" def run_task(self): - list_extensions(app_options=AppOptions( - app_dir=self.app_dir, logger=self.log, core_config=self.core_config, - labextensions_path=self.labextensions_path)) + list_extensions( + app_options=AppOptions( + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ) + ) class EnableLabExtensionsApp(BaseExtensionApp): description = "Enable labextension(s) by name" aliases = enable_aliases - level = Unicode('sys_prefix', help="Level at which to enable: sys_prefix, user, system").tag(config=True) + level = Unicode("sys_prefix", help="Level at which to enable: sys_prefix, user, system").tag( + config=True + ) def run_task(self): app_options = AppOptions( - app_dir=self.app_dir, logger=self.log, core_config=self.core_config, - labextensions_path=self.labextensions_path) - [enable_extension(arg, app_options=app_options, level=self.level) for arg in self.extra_args] + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ) + [ + enable_extension(arg, app_options=app_options, level=self.level) + for arg in self.extra_args + ] class DisableLabExtensionsApp(BaseExtensionApp): description = "Disable labextension(s) by name" aliases = disable_aliases - level = Unicode('sys_prefix', help="Level at which to enable: sys_prefix, user, system").tag(config=True) + level = Unicode("sys_prefix", help="Level at which to enable: sys_prefix, user, system").tag( + config=True + ) def run_task(self): app_options = AppOptions( - app_dir=self.app_dir, logger=self.log, core_config=self.core_config, - labextensions_path=self.labextensions_path) - [disable_extension(arg, app_options=app_options, level=self.level) for arg in self.extra_args] + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ) + [ + disable_extension(arg, app_options=app_options, level=self.level) + for arg in self.extra_args + ] class CheckLabExtensionsApp(BaseExtensionApp): description = "Check labextension(s) by name" flags = check_flags - should_check_installed_only = Bool(False, config=True, - help="Whether it should check only if the extensions is installed") + should_check_installed_only = Bool( + False, config=True, help="Whether it should check only if the extensions is installed" + ) def run_task(self): app_options = AppOptions( - app_dir=self.app_dir, logger=self.log, core_config=self.core_config, - labextensions_path=self.labextensions_path) + app_dir=self.app_dir, + logger=self.log, + core_config=self.core_config, + labextensions_path=self.labextensions_path, + ) all_enabled = all( check_extension( - arg, - installed=self.should_check_installed_only, - app_options=app_options) - for arg in self.extra_args) + arg, installed=self.should_check_installed_only, app_options=app_options + ) + for arg in self.extra_args + ) if not all_enabled: 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 """ class LabExtensionApp(JupyterApp): """Base jupyter labextension command entry point""" + name = "jupyter labextension" version = VERSION description = "Work with JupyterLab extensions" - examples = _examples + 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"), @@ -430,6 +487,9 @@ class LabExtensionApp(JupyterApp): 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): @@ -444,5 +504,5 @@ def start(self): main = LabExtensionApp.launch_instance -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) diff --git a/jupyterlab/node-version-check.js b/jupyterlab/node-version-check.js index ac858a2..95b5340 100644 --- a/jupyterlab/node-version-check.js +++ b/jupyterlab/node-version-check.js @@ -1,4 +1,9 @@ #!/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 fc93b2d..4ca1b3a 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 @@ -15,35 +18,40 @@ def mkdir(tmp_path, *parts): path.mkdir(parents=True) return path -app_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, 'app_settings')) -user_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, 'user_settings')) -schemas_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, 'schemas')) -workspaces_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, 'workspaces')) + +app_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "app_settings")) +user_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "user_settings")) +schemas_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "schemas")) +workspaces_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "workspaces")) + @pytest.fixture -def make_lab_app(jp_root_dir, jp_template_dir, app_settings_dir, user_settings_dir, schemas_dir, workspaces_dir): +def make_lab_app( + jp_root_dir, jp_template_dir, app_settings_dir, user_settings_dir, schemas_dir, workspaces_dir +): def _make_lab_app(**kwargs): class TestLabApp(LabApp): - base_url = '/lab' - extension_url = '/lab' - default_url = Unicode('/', - help='The default URL to redirect to from `/`') + base_url = "/lab" + extension_url = "/lab" + default_url = Unicode("/", help="The default URL to redirect to from `/`") lab_config = LabConfig( - app_name = 'JupyterLab Test App', - static_dir = str(jp_root_dir), - templates_dir = str(jp_template_dir), - app_url = '/lab', - app_settings_dir = str(app_settings_dir), - user_settings_dir = str(user_settings_dir), - schemas_dir = str(schemas_dir), - workspaces_dir = str(workspaces_dir), + app_name="JupyterLab Test App", + static_dir=str(jp_root_dir), + templates_dir=str(jp_template_dir), + app_url="/lab", + app_settings_dir=str(app_settings_dir), + user_settings_dir=str(user_settings_dir), + schemas_dir=str(schemas_dir), + workspaces_dir=str(workspaces_dir), ) + app = TestLabApp() return app # Create the index files. - index = jp_template_dir.joinpath('index.html') - index.write_text(""" + index = jp_template_dir.joinpath("index.html") + index.write_text( + """ @@ -73,7 +81,8 @@ class TestLabApp(LabApp): -""") +""" + ) return _make_lab_app @@ -89,16 +98,17 @@ def labapp(jp_serverapp, make_lab_app): @pytest.fixture 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 - ) + return http_server_client.fetch(url, headers=headers, request_timeout=250, **kwargs) + return client_fetch diff --git a/jupyterlab/semver.py b/jupyterlab/semver.py index 7726d79..c60f2ed 100644 --- a/jupyterlab/semver.py +++ b/jupyterlab/semver.py @@ -1,4 +1,7 @@ # -*- 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: @@ -27,16 +30,18 @@ import logging import re + logger = logging.getLogger(__name__) -SEMVER_SPEC_VERSION = '2.0.0' +SEMVER_SPEC_VERSION = "2.0.0" # Python 2/3 compatibility try: - string_type = basestring + string_type = basestring except NameError: - string_type = str + string_type = str + class _R(object): def __init__(self, i): @@ -80,10 +85,10 @@ def list_get(xs, i): # A single `0`, or a non-zero digit followed by zero or more digits. NUMERICIDENTIFIER = R() -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' +src[NUMERICIDENTIFIER] = "0|[1-9]\\d*" NUMERICIDENTIFIERLOOSE = R() -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' +src[NUMERICIDENTIFIERLOOSE] = "[0-9]+" # ## Non-numeric Identifier @@ -91,32 +96,48 @@ def list_get(xs, i): # more letters, digits, or hyphens. NONNUMERICIDENTIFIER = R() -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' +src[NONNUMERICIDENTIFIER] = "\\d*[a-zA-Z-][a-zA-Z0-9-]*" # ## Main Version # Three dot-separated numeric identifiers. MAINVERSION = R() -src[MAINVERSION] = ('(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')') +src[MAINVERSION] = ( + "(" + + src[NUMERICIDENTIFIER] + + ")\\." + + "(" + + src[NUMERICIDENTIFIER] + + ")\\." + + "(" + + src[NUMERICIDENTIFIER] + + ")" +) MAINVERSIONLOOSE = R() -src[MAINVERSIONLOOSE] = ('(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')') +src[MAINVERSIONLOOSE] = ( + "(" + + src[NUMERICIDENTIFIERLOOSE] + + ")\\." + + "(" + + src[NUMERICIDENTIFIERLOOSE] + + ")\\." + + "(" + + src[NUMERICIDENTIFIERLOOSE] + + ")" +) # ## Pre-release Version Identifier # A numeric identifier, or a non-numeric identifier. PRERELEASEIDENTIFIER = R() -src[PRERELEASEIDENTIFIER] = ('(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')') +src[PRERELEASEIDENTIFIER] = "(?:" + src[NUMERICIDENTIFIER] + "|" + src[NONNUMERICIDENTIFIER] + ")" PRERELEASEIDENTIFIERLOOSE = R() -src[PRERELEASEIDENTIFIERLOOSE] = ('(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')') +src[PRERELEASEIDENTIFIERLOOSE] = ( + "(?:" + src[NUMERICIDENTIFIERLOOSE] + "|" + src[NONNUMERICIDENTIFIER] + ")" +) # ## Pre-release Version @@ -124,26 +145,27 @@ def list_get(xs, i): # identifiers. PRERELEASE = R() -src[PRERELEASE] = ('(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))') +src[PRERELEASE] = ( + "(?:-(" + src[PRERELEASEIDENTIFIER] + "(?:\\." + src[PRERELEASEIDENTIFIER] + ")*))" +) PRERELEASELOOSE = R() -src[PRERELEASELOOSE] = ('(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))') +src[PRERELEASELOOSE] = ( + "(?:-?(" + src[PRERELEASEIDENTIFIERLOOSE] + "(?:\\." + src[PRERELEASEIDENTIFIERLOOSE] + ")*))" +) # ## Build Metadata Identifier # Any combination of digits, letters, or hyphens. BUILDIDENTIFIER = R() -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' +src[BUILDIDENTIFIER] = "[0-9A-Za-z-]+" # ## Build Metadata # Plus sign, followed by one or more period-separated build metadata # identifiers. BUILD = R() -src[BUILD] = ('(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))') +src[BUILD] = "(?:\\+(" + src[BUILDIDENTIFIER] + "(?:\\." + src[BUILDIDENTIFIER] + ")*))" # ## Full Version String # A main version, followed optionally by a pre-release version and @@ -155,98 +177,117 @@ def list_get(xs, i): # comparison. FULL = R() -FULLPLAIN = ('v?' + src[MAINVERSION] + src[PRERELEASE] + '?' + src[BUILD] + '?') +FULLPLAIN = "v?" + src[MAINVERSION] + src[PRERELEASE] + "?" + src[BUILD] + "?" -src[FULL] = '^' + FULLPLAIN + '$' +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. -LOOSEPLAIN = ('[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?') +LOOSEPLAIN = "[v=\\s]*" + src[MAINVERSIONLOOSE] + src[PRERELEASELOOSE] + "?" + src[BUILD] + "?" LOOSE = R() -src[LOOSE] = '^' + LOOSEPLAIN + '$' +src[LOOSE] = "^" + LOOSEPLAIN + "$" GTLT = R() -src[GTLT] = '((?:<|>)?=?)' +src[GTLT] = "((?:<|>)?=?)" # Something like "2.*" or "1.2.x". # Note that "x.x" is a valid xRange identifier, meaning "any version" # Only the first item is strictly required. XRANGEIDENTIFIERLOOSE = R() -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + "|x|X|\\*" XRANGEIDENTIFIER = R() -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + "|x|X|\\*" XRANGEPLAIN = R() -src[XRANGEPLAIN] = ('[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + - ')?)?') +src[XRANGEPLAIN] = ( + "[v=\\s]*(" + + src[XRANGEIDENTIFIER] + + ")" + + "(?:\\.(" + + src[XRANGEIDENTIFIER] + + ")" + + "(?:\\.(" + + src[XRANGEIDENTIFIER] + + ")" + + "(?:" + + src[PRERELEASE] + + ")?" + + src[BUILD] + + "?" + + ")?)?" +) XRANGEPLAINLOOSE = R() -src[XRANGEPLAINLOOSE] = ('[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + - ')?)?') +src[XRANGEPLAINLOOSE] = ( + "[v=\\s]*(" + + src[XRANGEIDENTIFIERLOOSE] + + ")" + + "(?:\\.(" + + src[XRANGEIDENTIFIERLOOSE] + + ")" + + "(?:\\.(" + + src[XRANGEIDENTIFIERLOOSE] + + ")" + + "(?:" + + src[PRERELEASELOOSE] + + ")?" + + src[BUILD] + + "?" + + ")?)?" +) XRANGE = R() -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' +src[XRANGE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAIN] + "$" XRANGELOOSE = R() -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' +src[XRANGELOOSE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAINLOOSE] + "$" # Tilde ranges. # Meaning is "reasonably at or greater than" LONETILDE = R() -src[LONETILDE] = '(?:~>?)' +src[LONETILDE] = "(?:~>?)" TILDETRIM = R() -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' +src[TILDETRIM] = "(\\s*)" + src[LONETILDE] + "\\s+" regexp[TILDETRIM] = re.compile(src[TILDETRIM], re.M) -tildeTrimReplace = r'\1~' +tildeTrimReplace = r"\1~" TILDE = R() -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' +src[TILDE] = "^" + src[LONETILDE] + src[XRANGEPLAIN] + "$" TILDELOOSE = R() -src[TILDELOOSE] = ('^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$') +src[TILDELOOSE] = "^" + src[LONETILDE] + src[XRANGEPLAINLOOSE] + "$" # Caret ranges. # Meaning is "at least and backwards compatible with" LONECARET = R() -src[LONECARET] = '(?:\\^)' +src[LONECARET] = "(?:\\^)" CARETTRIM = R() -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' +src[CARETTRIM] = "(\\s*)" + src[LONECARET] + "\\s+" regexp[CARETTRIM] = re.compile(src[CARETTRIM], re.M) -caretTrimReplace = r'\1^' +caretTrimReplace = r"\1^" CARET = R() -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' +src[CARET] = "^" + src[LONECARET] + src[XRANGEPLAIN] + "$" CARETLOOSE = R() -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' +src[CARETLOOSE] = "^" + src[LONECARET] + src[XRANGEPLAINLOOSE] + "$" # A simple gt/lt/eq thing, or just "" to indicate "any version" COMPARATORLOOSE = R() -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' +src[COMPARATORLOOSE] = "^" + src[GTLT] + "\\s*(" + LOOSEPLAIN + ")$|^$" COMPARATOR = R() -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' +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` COMPARATORTRIM = R() -src[COMPARATORTRIM] = ('(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')') +src[COMPARATORTRIM] = "(\\s*)" + src[GTLT] + "\\s*(" + LOOSEPLAIN + "|" + src[XRANGEPLAIN] + ")" # this one has to use the /g flag regexp[COMPARATORTRIM] = re.compile(src[COMPARATORTRIM], re.M) -comparatorTrimReplace = r'\1\2\3' +comparatorTrimReplace = r"\1\2\3" # Something like `1.2.3 - 1.2.4` @@ -254,24 +295,31 @@ def list_get(xs, i): # checked against either the strict or loose comparator form # later. HYPHENRANGE = R() -src[HYPHENRANGE] = ('^\\s*(' + src[XRANGEPLAIN] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + - '\\s*$') +src[HYPHENRANGE] = ( + "^\\s*(" + src[XRANGEPLAIN] + ")" + "\\s+-\\s+" + "(" + src[XRANGEPLAIN] + ")" + "\\s*$" +) HYPHENRANGELOOSE = R() -src[HYPHENRANGELOOSE] = ('^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$') +src[HYPHENRANGELOOSE] = ( + "^\\s*(" + + src[XRANGEPLAINLOOSE] + + ")" + + "\\s+-\\s+" + + "(" + + src[XRANGEPLAINLOOSE] + + ")" + + "\\s*$" +) # Star ranges basically just allow anything at all. STAR = R() -src[STAR] = '(<|>)?=?\\s*\\*' +src[STAR] = "(<|>)?=?\\s*\\*" # version name recovery for convenient RECOVERYVERSIONNAME = R() -src[RECOVERYVERSIONNAME] = ('v?({n})(?:\\.({n}))?{pre}?'.format(n=src[NUMERICIDENTIFIER], pre=src[PRERELEASELOOSE])) +src[RECOVERYVERSIONNAME] = "v?({n})(?:\\.({n}))?{pre}?".format( + n=src[NUMERICIDENTIFIER], pre=src[PRERELEASELOOSE] +) # Compile to actual regexp objects. # All are flag-free, unless they were created above with a flag. @@ -309,7 +357,7 @@ def clean(version, loose): return None -NUMERIC = re.compile("^\d+$") +NUMERIC = re.compile(r"^\d+$") def semver(version, loose): @@ -348,8 +396,9 @@ def __init__(self, version, loose): if not m.group(3): self.prerelease = [] else: - self.prerelease = [(int(id) if NUMERIC.search(id) else id) - for id in m.group(3).split(".")] + self.prerelease = [ + (int(id) if NUMERIC.search(id) else id) for id in m.group(3).split(".") + ] else: # these are actually numbers self.major = int(m.group(1)) @@ -360,8 +409,9 @@ def __init__(self, version, loose): self.prerelease = [] else: - self.prerelease = [(int(id) if NUMERIC.search(id) else id) - for id in m.group(4).split(".")] + self.prerelease = [ + (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(".") else: @@ -372,7 +422,7 @@ def __init__(self, version, loose): def format(self): self.version = "{}.{}.{}".format(self.major, self.minor, self.patch) if len(self.prerelease) > 0: - self.version += ("-{}".format(".".join(str(v) for v in self.prerelease))) + self.version += "-{}".format(".".join(str(v) for v in self.prerelease)) return self.version def __repr__(self): @@ -382,7 +432,7 @@ def __str__(self): return self.version def compare(self, other): - logger.debug('SemVer.compare %s %s %s', self.version, self.loose, other) + logger.debug("SemVer.compare %s %s %s", self.version, self.loose, other) if not isinstance(other, SemVer): other = make_semver(other, self.loose) result = self.compare_main(other) or self.compare_pre(other) @@ -393,9 +443,11 @@ def compare_main(self, other): if not isinstance(other, SemVer): other = make_semver(other, self.loose) - return (compare_identifiers(str(self.major), str(other.major)) or - compare_identifiers(str(self.minor), str(other.minor)) or - compare_identifiers(str(self.patch), str(other.patch))) + return ( + compare_identifiers(str(self.major), str(other.major)) + or compare_identifiers(str(self.minor), str(other.minor)) + or compare_identifiers(str(self.patch), str(other.patch)) + ) def compare_pre(self, other): if not isinstance(other, SemVer): @@ -431,25 +483,25 @@ def compare_pre(self, other): def inc(self, release, identifier=None): logger.debug("inc release %s %s", self.prerelease, release) - if release == 'premajor': + if release == "premajor": self.prerelease = [] self.patch = 0 self.minor = 0 self.major += 1 - self.inc('pre', identifier=identifier) + self.inc("pre", identifier=identifier) elif release == "preminor": self.prerelease = [] self.patch = 0 self.minor += 1 - self.inc('pre', identifier=identifier) + self.inc("pre", identifier=identifier) elif release == "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. self.prerelease = [] - self.inc('patch', identifier=identifier) - self.inc('pre', identifier=identifier) - elif release == 'prerelease': + self.inc("patch", identifier=identifier) + self.inc("pre", identifier=identifier) + elif release == "prerelease": # If the input is a non-prerelease version, this acts the same as # prepatch. if len(self.prerelease) == 0: @@ -507,7 +559,7 @@ def inc(self, release, identifier=None): else: self.prerelease = [identifier, 0] else: - raise ValueError('invalid increment argument: {}'.format(release)) + raise ValueError("invalid increment argument: {}".format(release)) self.format() self.raw = self.version return self @@ -565,11 +617,13 @@ def key_function(version): key = key + tuple(v.prerelease) else: # NOT having a prerelease is > having one - key = key + (float('inf'),) + key = key + (float("inf"),) return key + return key_function + loose_key_function = make_key_function(True) full_key_function = make_key_function(True) @@ -634,7 +688,7 @@ def cmp(a, op, b, loose): def comparator(comp, loose): if isinstance(comp, Comparator): - if(comp.loose == loose): + if comp.loose == loose: return comp else: comp = comp.value @@ -687,7 +741,7 @@ def __str__(self): return self.value def test(self, version): - logger.debug('Comparator, test %s, %s', version, self.loose) + logger.debug("Comparator, test %s, %s", version, self.loose) if self.semver == ANY: return True else: @@ -720,7 +774,9 @@ def __repr__(self): return ''.format(self.range) def format(self): - self.range = "||".join([" ".join(c.value for c in comps).strip() for comps in self.set]).strip() + self.range = "||".join( + [" ".join(c.value for c in comps).strip() for comps in self.set] + ).strip() logger.debug("Range format %s", self.range) return self.range @@ -729,19 +785,22 @@ def __str__(self): def parse_range(self, range_): loose = self.loose - logger.debug('range %s %s', range_, 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] - range_ = hr.sub(hyphen_replace, range_,) - logger.debug('hyphen replace %s', range_) + range_ = hr.sub( + hyphen_replace, + range_, + ) + logger.debug("hyphen replace %s", range_) # `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` range_ = regexp[COMPARATORTRIM].sub(comparatorTrimReplace, range_) - logger.debug('comparator trim %s, %s', range_, regexp[COMPARATORTRIM]) + logger.debug("comparator trim %s, %s", range_, regexp[COMPARATORTRIM]) # `~ 1.2.3` => `~1.2.3` range_ = regexp[TILDETRIM].sub(tildeTrimReplace, range_) @@ -750,7 +809,7 @@ 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. @@ -758,7 +817,9 @@ def parse_range(self, range_): comp_re = regexp[COMPARATORLOOSE] else: comp_re = regexp[COMPARATOR] - set_ = re.split("\s+", ' '.join([parse_comparator(comp, loose) for comp in range_.split(" ")])) + set_ = re.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 set_ = [comp for comp in set_ if comp_re.search(comp)] @@ -780,24 +841,27 @@ def test(self, version): # Mostly just for testing and legacy API reasons def to_comparators(range_, loose): - return [" ".join([c.value for c in comp]).strip().split(" ") - for comp in make_range(range_, loose).set] + return [ + " ".join([c.value for c in comp]).strip().split(" ") + for comp in make_range(range_, loose).set + ] # comprised of xranges, tildes, stars, and gtlt's at this point. # already replaced the hyphen ranges # turn into a set of JUST comparators. + def parse_comparator(comp, loose): - logger.debug('comp %s', comp) + logger.debug("comp %s", comp) comp = replace_carets(comp, loose) - logger.debug('caret %s', comp) + logger.debug("caret %s", comp) comp = replace_tildes(comp, loose) - logger.debug('tildes %s', comp) + logger.debug("tildes %s", comp) comp = replace_xranges(comp, loose) - logger.debug('xrange %s', comp) + logger.debug("xrange %s", comp) comp = replace_stars(comp, loose) - logger.debug('stars %s', comp) + logger.debug("stars %s", comp) return comp @@ -812,9 +876,9 @@ def is_x(id): # ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 # ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 + 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): @@ -830,20 +894,21 @@ 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): # ~1.2 == >=1.2.0 <1.3.0 - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + str(int(m) + 1) + '.0' + ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0" elif pr: logger.debug("replaceTilde pr %s", pr) - if (pr[0] != "-"): - pr = '-' + pr - ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + str(int(m) + 1) + '.0' + if pr[0] != "-": + pr = "-" + pr + ret = ">=" + M + "." + m + "." + p + pr + " <" + M + "." + str(int(m) + 1) + ".0" else: # ~1.2.3 == >=1.2.3 <1.3.0 - ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + str(int(m) + 1) + '.0' - logger.debug('tilde return, %s', ret) + ret = ">=" + M + "." + m + "." + p + " <" + M + "." + str(int(m) + 1) + ".0" + logger.debug("tilde return, %s", ret) return ret + return r.sub(repl, comp) @@ -854,8 +919,7 @@ 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): @@ -872,41 +936,92 @@ 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' + ret = ">=" + M + "." + m + ".0 <" + str(int(M) + 1) + ".0.0" elif pr: - logger.debug('replaceCaret pr %s', pr) + logger.debug("replaceCaret pr %s", pr) if pr[0] != "-": pr = "-" + pr if M == "0": if m == "0": - ret = '>=' + M + '.' + m + '.' + (p or "") + pr + ' <' + M + '.' + m + "." + str(int(p or 0) + 1) + ret = ( + ">=" + + M + + "." + + m + + "." + + (p or "") + + pr + + " <" + + M + + "." + + m + + "." + + str(int(p or 0) + 1) + ) else: - ret = '>=' + M + '.' + m + '.' + (p or "") + pr + ' <' + M + '.' + str(int(m) + 1) + '.0' + ret = ( + ">=" + + M + + "." + + m + + "." + + (p or "") + + pr + + " <" + + M + + "." + + str(int(m) + 1) + + ".0" + ) else: - ret = '>=' + M + '.' + m + '.' + (p or "") + pr + ' <' + str(int(M) + 1) + '.0.0' + ret = ">=" + M + "." + m + "." + (p or "") + pr + " <" + str(int(M) + 1) + ".0.0" else: if M == "0": if m == "0": - ret = '>=' + M + '.' + m + '.' + (p or "") + ' <' + M + '.' + m + "." + str(int(p or 0) + 1) + ret = ( + ">=" + + M + + "." + + m + + "." + + (p or "") + + " <" + + M + + "." + + m + + "." + + str(int(p or 0) + 1) + ) else: - ret = '>=' + M + '.' + m + '.' + (p or "") + ' <' + M + '.' + str((int(m) + 1)) + '.0' + ret = ( + ">=" + + M + + "." + + m + + "." + + (p or "") + + " <" + + M + + "." + + str((int(m) + 1)) + + ".0" + ) else: - ret = '>=' + M + '.' + m + '.' + (p or "") + ' <' + str(int(M) + 1) + '.0.0' - logger.debug('caret return %s', ret) + ret = ">=" + M + "." + m + "." + (p or "") + " <" + str(int(M) + 1) + ".0.0" + logger.debug("caret return %s", ret) return ret return r.sub(repl, comp) 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())]) + logger.debug("replaceXRanges %s %s", comp, loose) + return " ".join([replace_xrange(c, loose) for c in re.split(r"\s+", comp.strip())]) def replace_xrange(comp, loose): @@ -932,11 +1047,11 @@ def repl(mob): logger.debug("xrange gtlt=%s any_x=%s", gtlt, any_x) if xM: - if gtlt == '>' or gtlt == '<': + if gtlt == ">" or gtlt == "<": # nothing is allowed - ret = '<0.0.0' + ret = "<0.0.0" else: - ret = '*' + ret = "*" elif gtlt and any_x: # replace X with 0, and then append the -0 min-prerelease if xm: @@ -956,30 +1071,31 @@ def repl(mob): elif xp: m = int(m) + 1 p = 0 - elif gtlt == '<=': + elif 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 = '<' + gtlt = "<" if xm: M = int(M) + 1 else: m = int(m) + 1 - ret = gtlt + str(M) + '.' + str(m) + '.' + str(p) + ret = gtlt + str(M) + "." + str(m) + "." + str(p) elif xm: - ret = '>=' + M + '.0.0 <' + str(int(M) + 1) + '.0.0' + ret = ">=" + M + ".0.0 <" + str(int(M) + 1) + ".0.0" elif xp: - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + str(int(m) + 1) + '.0' - logger.debug('xRange return %s', ret) + ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0" + logger.debug("xRange return %s", ret) return ret + return r.sub(repl, comp) # Because * is AND-ed with everything else in the comparator, # and '' means "any version", just remove the *s entirely. def replace_stars(comp, loose): - logger.debug('replaceStars %s %s', comp, loose) + logger.debug("replaceStars %s %s", comp, loose) # Looseness is ignored here. star is always as loose as it gets! return regexp[STAR].sub("", comp.strip()) @@ -994,23 +1110,23 @@ def hyphen_replace(mob): if is_x(fM): from_ = "" elif is_x(fm): - from_ = '>=' + fM + '.0.0' + from_ = ">=" + fM + ".0.0" elif is_x(fp): - from_ = '>=' + fM + '.' + fm + '.0' + from_ = ">=" + fM + "." + fm + ".0" else: from_ = ">=" + from_ if is_x(tM): to = "" elif is_x(tm): - to = '<' + str(int(tM) + 1) + '.0.0' + to = "<" + str(int(tM) + 1) + ".0.0" elif is_x(tp): - to = '<' + tM + '.' + str(int(tm) + 1) + '.0' + to = "<" + tM + "." + str(int(tm) + 1) + ".0" elif tpr: - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + to = "<=" + tM + "." + tm + "." + tp + "-" + tpr else: - to = '<=' + to - return (from_ + ' ' + to).strip() + to = "<=" + to + return (from_ + " " + to).strip() def test_set(set_, version): @@ -1028,7 +1144,11 @@ def test_set(set_, version): continue if len(e.semver.prerelease) > 0: allowed = e.semver - if allowed.major == version.major and allowed.minor == version.minor and allowed.patch == version.patch: + if ( + allowed.major == version.major + and allowed.minor == version.minor + and allowed.patch == version.patch + ): return True # Version has a -pre, but it's not one of the ones we like. return False @@ -1038,7 +1158,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) @@ -1046,7 +1166,7 @@ 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 @@ -1063,7 +1183,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 diff --git a/jupyterlab/serverextension.py b/jupyterlab/serverextension.py index 0ace9e4..3d20544 100644 --- a/jupyterlab/serverextension.py +++ b/jupyterlab/serverextension.py @@ -1,5 +1,8 @@ -from tornado.web import RedirectHandler +# 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 def load_jupyter_server_extension(serverapp): @@ -13,22 +16,56 @@ def load_jupyter_server_extension(serverapp): extension.load_config_file() extension.update_config(serverapp.config) extension.parse_command_line(serverapp.extra_args) - extension.handlers.extend([ - (r"/static/favicons/favicon.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon.ico")}), - (r"/static/favicons/favicon-busy-1.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-1.ico")}), - (r"/static/favicons/favicon-busy-2.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-2.ico")}), - (r"/static/favicons/favicon-busy-3.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-3.ico")}), - (r"/static/favicons/favicon-file.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-file.ico")}), - (r"/static/favicons/favicon-notebook.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-notebook.ico")}), - (r"/static/favicons/favicon-terminal.ico", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-terminal.ico")}), - (r"/static/logo/logo.png", RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/logo.png")}), - ]) + extension.handlers.extend( + [ + ( + r"/static/favicons/favicon.ico", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/favicon.ico")}, + ), + ( + r"/static/favicons/favicon-busy-1.ico", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-1.ico")}, + ), + ( + r"/static/favicons/favicon-busy-2.ico", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-2.ico")}, + ), + ( + r"/static/favicons/favicon-busy-3.ico", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-3.ico")}, + ), + ( + r"/static/favicons/favicon-file.ico", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-file.ico")}, + ), + ( + r"/static/favicons/favicon-notebook.ico", + RedirectHandler, + { + "url": url_path_join( + serverapp.base_url, "static/base/images/favicon-notebook.ico" + ) + }, + ), + ( + r"/static/favicons/favicon-terminal.ico", + RedirectHandler, + { + "url": url_path_join( + serverapp.base_url, "static/base/images/favicon-terminal.ico" + ) + }, + ), + ( + r"/static/logo/logo.png", + RedirectHandler, + {"url": url_path_join(serverapp.base_url, "static/base/images/logo.png")}, + ), + ] + ) extension.initialize() diff --git a/jupyterlab/staging/assets/architecture.jpg b/jupyterlab/staging/assets/architecture.jpg deleted file mode 100644 index 10c3de0..0000000 Binary files a/jupyterlab/staging/assets/architecture.jpg and /dev/null differ diff --git a/jupyterlab/staging/assets/exilir-note-2.svg b/jupyterlab/staging/assets/exilir-note-2.svg deleted file mode 100644 index da3b2f6..0000000 --- a/jupyterlab/staging/assets/exilir-note-2.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - exilir-note-2 - - - - - - \ No newline at end of file diff --git a/jupyterlab/staging/bootstrap.js b/jupyterlab/staging/bootstrap.js index 1b07e4b..9a5ae3e 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 daad05e..23a5259 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) { @@ -213,6 +195,7 @@ export async function main() { var devMode = (PageConfig.getOption('devMode') || '').toLowerCase() === 'true'; if (exposeAppInBrowser || devMode) { + // This is deprecated in favor of more generic window.jupyterapp window.jupyterlab = lab; window.jupyterapp = lab; } diff --git a/jupyterlab/staging/package.json b/jupyterlab/staging/package.json index 9f9a384..ba51699 100644 --- a/jupyterlab/staging/package.json +++ b/jupyterlab/staging/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/application-top", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "private": true, "license": "BSD-3-Clause", "scripts": { @@ -16,166 +16,176 @@ "watch": "webpack --watch" }, "resolutions": { - "@jupyterlab/application": "~3.3.2", - "@jupyterlab/application-extension": "~3.3.2", - "@jupyterlab/apputils": "~3.3.2", - "@jupyterlab/apputils-extension": "~3.3.2", - "@jupyterlab/attachments": "~3.3.2", - "@jupyterlab/cells": "~3.3.2", - "@jupyterlab/celltags": "~3.3.2", - "@jupyterlab/celltags-extension": "~3.3.2", - "@jupyterlab/codeeditor": "~3.3.2", - "@jupyterlab/codemirror": "~3.3.2", - "@jupyterlab/codemirror-extension": "~3.3.2", - "@jupyterlab/completer": "~3.3.2", - "@jupyterlab/completer-extension": "~3.3.2", - "@jupyterlab/console": "~3.3.2", - "@jupyterlab/console-extension": "~3.3.2", - "@jupyterlab/coreutils": "~5.3.2", - "@jupyterlab/csvviewer": "~3.3.2", - "@jupyterlab/csvviewer-extension": "~3.3.2", - "@jupyterlab/debugger": "~3.3.2", - "@jupyterlab/debugger-extension": "~3.3.2", - "@jupyterlab/docmanager": "~3.3.2", - "@jupyterlab/docmanager-extension": "~3.3.2", - "@jupyterlab/docprovider": "~3.3.2", - "@jupyterlab/docprovider-extension": "~3.3.2", - "@jupyterlab/docregistry": "~3.3.2", - "@jupyterlab/documentsearch": "~3.3.2", - "@jupyterlab/documentsearch-extension": "~3.3.2", - "@jupyterlab/extensionmanager": "~3.3.2", - "@jupyterlab/extensionmanager-extension": "~3.3.2", - "@jupyterlab/filebrowser": "~3.3.2", - "@jupyterlab/filebrowser-extension": "~3.3.2", - "@jupyterlab/fileeditor": "~3.3.2", - "@jupyterlab/fileeditor-extension": "~3.3.2", - "@jupyterlab/help-extension": "~3.3.2", - "@jupyterlab/htmlviewer": "~3.3.2", - "@jupyterlab/htmlviewer-extension": "~3.3.2", - "@jupyterlab/hub-extension": "~3.3.2", - "@jupyterlab/imageviewer": "~3.3.2", - "@jupyterlab/imageviewer-extension": "~3.3.2", - "@jupyterlab/inspector": "~3.3.2", - "@jupyterlab/inspector-extension": "~3.3.2", - "@jupyterlab/javascript-extension": "~3.3.2", - "@jupyterlab/json-extension": "~3.3.2", - "@jupyterlab/launcher": "~3.3.2", - "@jupyterlab/launcher-extension": "~3.3.2", - "@jupyterlab/logconsole": "~3.3.2", - "@jupyterlab/logconsole-extension": "~3.3.2", - "@jupyterlab/mainmenu": "~3.3.2", - "@jupyterlab/mainmenu-extension": "~3.3.2", - "@jupyterlab/markdownviewer": "~3.3.2", - "@jupyterlab/markdownviewer-extension": "~3.3.2", - "@jupyterlab/mathjax2": "~3.3.2", - "@jupyterlab/mathjax2-extension": "~3.3.2", - "@jupyterlab/metapackage": "~3.3.2", - "@jupyterlab/nbconvert-css": "~3.3.2", - "@jupyterlab/nbformat": "~3.3.2", - "@jupyterlab/notebook": "~3.3.2", - "@jupyterlab/notebook-extension": "~3.3.2", - "@jupyterlab/observables": "~4.3.2", - "@jupyterlab/outputarea": "~3.3.2", - "@jupyterlab/pdf-extension": "~3.3.2", - "@jupyterlab/property-inspector": "~3.3.2", - "@jupyterlab/rendermime": "~3.3.2", - "@jupyterlab/rendermime-extension": "~3.3.2", - "@jupyterlab/rendermime-interfaces": "~3.3.2", - "@jupyterlab/running": "~3.3.2", - "@jupyterlab/running-extension": "~3.3.2", - "@jupyterlab/services": "~6.3.2", - "@jupyterlab/settingeditor": "~3.3.2", - "@jupyterlab/settingeditor-extension": "~3.3.2", - "@jupyterlab/settingregistry": "~3.3.2", - "@jupyterlab/shared-models": "~3.3.2", - "@jupyterlab/shortcuts-extension": "~3.3.2", - "@jupyterlab/statedb": "~3.3.2", - "@jupyterlab/statusbar": "~3.3.2", - "@jupyterlab/statusbar-extension": "~3.3.2", - "@jupyterlab/terminal": "~3.3.2", - "@jupyterlab/terminal-extension": "~3.3.2", - "@jupyterlab/theme-dark-extension": "~3.3.2", - "@jupyterlab/theme-light-extension": "~3.3.2", - "@jupyterlab/toc": "~5.3.2", - "@jupyterlab/toc-extension": "~5.3.2", - "@jupyterlab/tooltip": "~3.3.2", - "@jupyterlab/tooltip-extension": "~3.3.2", - "@jupyterlab/translation": "~3.3.2", - "@jupyterlab/translation-extension": "~3.3.2", - "@jupyterlab/ui-components": "~3.3.2", - "@jupyterlab/ui-components-extension": "~3.3.2", - "@jupyterlab/vdom": "~3.3.2", - "@jupyterlab/vdom-extension": "~3.3.2", - "@jupyterlab/vega5-extension": "~3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/application": "^1.16.0", - "@lumino/commands": "^1.12.0", - "@lumino/coreutils": "^1.5.3", - "@lumino/disposable": "^1.4.3", - "@lumino/domutils": "^1.2.3", - "@lumino/dragdrop": "^1.7.1", - "@lumino/messaging": "^1.4.3", - "@lumino/properties": "^1.2.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "~4.0.0-alpha.12", + "@jupyterlab/application-extension": "~4.0.0-alpha.12", + "@jupyterlab/apputils": "~4.0.0-alpha.12", + "@jupyterlab/apputils-extension": "~4.0.0-alpha.12", + "@jupyterlab/attachments": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/cells": "~4.0.0-alpha.12", + "@jupyterlab/celltags": "~4.0.0-alpha.12", + "@jupyterlab/celltags-extension": "~4.0.0-alpha.12", + "@jupyterlab/codeeditor": "~4.0.0-alpha.12", + "@jupyterlab/codemirror": "~4.0.0-alpha.12", + "@jupyterlab/codemirror-extension": "~4.0.0-alpha.12", + "@jupyterlab/collaboration": "~4.0.0-alpha.12", + "@jupyterlab/collaboration-extension": "~4.0.0-alpha.12", + "@jupyterlab/completer": "~4.0.0-alpha.12", + "@jupyterlab/completer-extension": "~4.0.0-alpha.12", + "@jupyterlab/console": "~4.0.0-alpha.12", + "@jupyterlab/console-extension": "~4.0.0-alpha.12", + "@jupyterlab/coreutils": "~6.0.0-alpha.12", + "@jupyterlab/csvviewer": "~4.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/debugger": "~4.0.0-alpha.12", + "@jupyterlab/debugger-extension": "~4.0.0-alpha.12", + "@jupyterlab/docmanager": "~4.0.0-alpha.12", + "@jupyterlab/docmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/docprovider": "~4.0.0-alpha.12", + "@jupyterlab/docprovider-extension": "~4.0.0-alpha.12", + "@jupyterlab/docregistry": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch-extension": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser-extension": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/help-extension": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/hub-extension": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/inspector": "~4.0.0-alpha.12", + "@jupyterlab/inspector-extension": "~4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "~4.0.0-alpha.12", + "@jupyterlab/json-extension": "~4.0.0-alpha.12", + "@jupyterlab/launcher": "~4.0.0-alpha.12", + "@jupyterlab/launcher-extension": "~4.0.0-alpha.12", + "@jupyterlab/logconsole": "~4.0.0-alpha.12", + "@jupyterlab/logconsole-extension": "~4.0.0-alpha.12", + "@jupyterlab/lsp": "~4.0.0-alpha.12", + "@jupyterlab/lsp-extension": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu-extension": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/markedparser-extension": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "~4.0.0-alpha.12", + "@jupyterlab/metapackage": "~4.0.0-alpha.12", + "@jupyterlab/nbconvert-css": "~4.0.0-alpha.12", + "@jupyterlab/nbformat": "~4.0.0-alpha.12", + "@jupyterlab/notebook": "~4.0.0-alpha.12", + "@jupyterlab/notebook-extension": "~4.0.0-alpha.12", + "@jupyterlab/observables": "~5.0.0-alpha.12", + "@jupyterlab/outputarea": "~4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "~4.0.0-alpha.12", + "@jupyterlab/property-inspector": "~4.0.0-alpha.12", + "@jupyterlab/rendermime": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-interfaces": "~3.8.0-alpha.12", + "@jupyterlab/running": "~4.0.0-alpha.12", + "@jupyterlab/running-extension": "~4.0.0-alpha.12", + "@jupyterlab/services": "~7.0.0-alpha.12", + "@jupyterlab/settingeditor": "~4.0.0-alpha.12", + "@jupyterlab/settingeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/settingregistry": "~4.0.0-alpha.12", + "@jupyterlab/shared-models": "~4.0.0-alpha.12", + "@jupyterlab/shortcuts-extension": "~4.0.0-alpha.12", + "@jupyterlab/statedb": "~4.0.0-alpha.12", + "@jupyterlab/statusbar": "~4.0.0-alpha.12", + "@jupyterlab/statusbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/terminal": "~4.0.0-alpha.12", + "@jupyterlab/terminal-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-dark-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "~4.0.0-alpha.12", + "@jupyterlab/toc": "~6.0.0-alpha.12", + "@jupyterlab/toc-extension": "~6.0.0-alpha.12", + "@jupyterlab/tooltip": "~4.0.0-alpha.12", + "@jupyterlab/tooltip-extension": "~4.0.0-alpha.12", + "@jupyterlab/translation": "~4.0.0-alpha.12", + "@jupyterlab/translation-extension": "~4.0.0-alpha.12", + "@jupyterlab/ui-components": "~4.0.0-alpha.27", + "@jupyterlab/ui-components-extension": "~4.0.0-alpha.12", + "@jupyterlab/vdom": "~4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "~4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "~4.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/application": "^1.27.0", + "@lumino/commands": "^1.19.0", + "@lumino/coreutils": "^1.11.1", + "@lumino/disposable": "^1.10.1", + "@lumino/domutils": "^1.8.1", + "@lumino/dragdrop": "^1.13.1", + "@lumino/messaging": "^1.10.1", + "@lumino/properties": "^1.8.1", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "react": "^17.0.1", "react-dom": "^17.0.1", - "yjs": "^13.5.17" + "yjs": "^13.5.34" }, "dependencies": { - "@jupyterlab/application": "~3.3.2", - "@jupyterlab/application-extension": "~3.3.2", - "@jupyterlab/apputils-extension": "~3.3.2", - "@jupyterlab/celltags-extension": "~3.3.2", - "@jupyterlab/codemirror-extension": "~3.3.2", - "@jupyterlab/completer-extension": "~3.3.2", - "@jupyterlab/console-extension": "~3.3.2", - "@jupyterlab/coreutils": "~5.3.2", - "@jupyterlab/csvviewer-extension": "~3.3.2", - "@jupyterlab/debugger-extension": "~3.3.2", - "@jupyterlab/docmanager-extension": "~3.3.2", - "@jupyterlab/docprovider-extension": "~3.3.2", - "@jupyterlab/documentsearch-extension": "~3.3.2", - "@jupyterlab/extensionmanager-extension": "~3.3.2", - "@jupyterlab/filebrowser-extension": "~3.3.2", - "@jupyterlab/fileeditor-extension": "~3.3.2", - "@jupyterlab/help-extension": "~3.3.2", - "@jupyterlab/htmlviewer-extension": "~3.3.2", - "@jupyterlab/hub-extension": "~3.3.2", - "@jupyterlab/imageviewer-extension": "~3.3.2", - "@jupyterlab/inspector-extension": "~3.3.2", - "@jupyterlab/javascript-extension": "~3.3.2", - "@jupyterlab/json-extension": "~3.3.2", - "@jupyterlab/launcher-extension": "~3.3.2", - "@jupyterlab/logconsole-extension": "~3.3.2", - "@jupyterlab/mainmenu-extension": "~3.3.2", - "@jupyterlab/markdownviewer-extension": "~3.3.2", - "@jupyterlab/mathjax2-extension": "~3.3.2", - "@jupyterlab/notebook-extension": "~3.3.2", - "@jupyterlab/pdf-extension": "~3.3.2", - "@jupyterlab/rendermime-extension": "~3.3.2", - "@jupyterlab/running-extension": "~3.3.2", - "@jupyterlab/settingeditor-extension": "~3.3.2", - "@jupyterlab/shortcuts-extension": "~3.3.2", - "@jupyterlab/statusbar-extension": "~3.3.2", - "@jupyterlab/terminal-extension": "~3.3.2", - "@jupyterlab/theme-dark-extension": "~3.3.2", - "@jupyterlab/theme-light-extension": "~3.3.2", - "@jupyterlab/toc-extension": "~5.3.2", - "@jupyterlab/tooltip-extension": "~3.3.2", - "@jupyterlab/translation-extension": "~3.3.2", - "@jupyterlab/ui-components-extension": "~3.3.2", - "@jupyterlab/vdom-extension": "~3.3.2", - "@jupyterlab/vega5-extension": "~3.3.2" + "@jupyterlab/application": "~4.0.0-alpha.12", + "@jupyterlab/application-extension": "~4.0.0-alpha.12", + "@jupyterlab/apputils-extension": "~4.0.0-alpha.12", + "@jupyterlab/cell-toolbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/celltags-extension": "~4.0.0-alpha.12", + "@jupyterlab/codemirror-extension": "~4.0.0-alpha.12", + "@jupyterlab/collaboration-extension": "~4.0.0-alpha.12", + "@jupyterlab/completer-extension": "~4.0.0-alpha.12", + "@jupyterlab/console-extension": "~4.0.0-alpha.12", + "@jupyterlab/coreutils": "~6.0.0-alpha.12", + "@jupyterlab/csvviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/debugger-extension": "~4.0.0-alpha.12", + "@jupyterlab/docmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/docprovider-extension": "~4.0.0-alpha.12", + "@jupyterlab/documentsearch-extension": "~4.0.0-alpha.12", + "@jupyterlab/extensionmanager-extension": "~4.0.0-alpha.12", + "@jupyterlab/filebrowser-extension": "~4.0.0-alpha.12", + "@jupyterlab/fileeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/help-extension": "~4.0.0-alpha.12", + "@jupyterlab/htmlviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/hub-extension": "~4.0.0-alpha.12", + "@jupyterlab/imageviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/inspector-extension": "~4.0.0-alpha.12", + "@jupyterlab/javascript-extension": "~4.0.0-alpha.12", + "@jupyterlab/json-extension": "~4.0.0-alpha.12", + "@jupyterlab/launcher-extension": "~4.0.0-alpha.12", + "@jupyterlab/logconsole-extension": "~4.0.0-alpha.12", + "@jupyterlab/lsp-extension": "~4.0.0-alpha.12", + "@jupyterlab/mainmenu-extension": "~4.0.0-alpha.12", + "@jupyterlab/markdownviewer-extension": "~4.0.0-alpha.12", + "@jupyterlab/markedparser-extension": "~4.0.0-alpha.12", + "@jupyterlab/mathjax2-extension": "~4.0.0-alpha.12", + "@jupyterlab/notebook-extension": "~4.0.0-alpha.12", + "@jupyterlab/pdf-extension": "~4.0.0-alpha.12", + "@jupyterlab/rendermime-extension": "~4.0.0-alpha.12", + "@jupyterlab/running-extension": "~4.0.0-alpha.12", + "@jupyterlab/settingeditor-extension": "~4.0.0-alpha.12", + "@jupyterlab/shortcuts-extension": "~4.0.0-alpha.12", + "@jupyterlab/statusbar-extension": "~4.0.0-alpha.12", + "@jupyterlab/terminal-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-dark-extension": "~4.0.0-alpha.12", + "@jupyterlab/theme-light-extension": "~4.0.0-alpha.12", + "@jupyterlab/toc-extension": "~6.0.0-alpha.12", + "@jupyterlab/tooltip-extension": "~4.0.0-alpha.12", + "@jupyterlab/translation-extension": "~4.0.0-alpha.12", + "@jupyterlab/ui-components-extension": "~4.0.0-alpha.12", + "@jupyterlab/vdom-extension": "~4.0.0-alpha.12", + "@jupyterlab/vega5-extension": "~4.0.0-alpha.12" }, "devDependencies": { - "@jupyterlab/builder": "^3.3.2", - "@jupyterlab/buildutils": "^3.3.2", + "@jupyterlab/builder": "^4.0.0-alpha.12", + "@jupyterlab/buildutils": "^4.0.0-alpha.12", "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", "glob": "~7.1.6", "handlebars": "^4.5.3", @@ -183,18 +193,16 @@ "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", + "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", + "style-loader": "~3.3.1", "terser-webpack-plugin": "^4.1.0", - "url-loader": "~4.1.0", - "webpack": "^5.41.1", + "webpack": "^5.72.0", "webpack-bundle-analyzer": "^3.6.0", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.1.2", + "webpack-cli": "^4.9.2", + "webpack-merge": "^5.8.0", "whatwg-fetch": "^3.0.0", "worker-loader": "^3.0.2", "yarn-deduplicate": "^2.1.1" @@ -203,13 +211,15 @@ "node": ">=12.0.0" }, "jupyterlab": { - "name": "JupyterLab", - "version": "3.3.2", + "name": "ElixirNote", + "version": "4.0.0a30", "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": "", @@ -227,8 +237,10 @@ "@jupyterlab/inspector-extension": "", "@jupyterlab/launcher-extension": "", "@jupyterlab/logconsole-extension": "", + "@jupyterlab/lsp-extension": "", "@jupyterlab/mainmenu-extension": "", "@jupyterlab/markdownviewer-extension": "", + "@jupyterlab/markedparser-extension": "", "@jupyterlab/mathjax2-extension": "", "@jupyterlab/notebook-extension": "", "@jupyterlab/rendermime-extension": "", @@ -251,14 +263,15 @@ "@jupyterlab/pdf-extension": "", "@jupyterlab/vega5-extension": "" }, - "externalExtensions": {}, "buildDir": "./build", "outputDir": "..", "singletonPackages": [ "@jupyterlab/application", "@jupyterlab/apputils", + "@jupyterlab/cell-toolbar", "@jupyterlab/codeeditor", "@jupyterlab/codemirror", + "@jupyterlab/collaboration", "@jupyterlab/completer", "@jupyterlab/console", "@jupyterlab/coreutils", @@ -273,6 +286,7 @@ "@jupyterlab/inspector", "@jupyterlab/launcher", "@jupyterlab/logconsole", + "@jupyterlab/lsp", "@jupyterlab/mainmenu", "@jupyterlab/markdownviewer", "@jupyterlab/notebook", @@ -305,7 +319,111 @@ "react-dom", "yjs" ], - "linkedPackages": {}, + "linkedPackages": { + "@jupyterlab/application": "../../packages/application", + "@jupyterlab/application-extension": "../../packages/application-extension", + "@jupyterlab/apputils": "../../packages/apputils", + "@jupyterlab/apputils-extension": "../../packages/apputils-extension", + "@jupyterlab/attachments": "../../packages/attachments", + "@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", + "@jupyterlab/console-extension": "../../packages/console-extension", + "@jupyterlab/coreutils": "../../packages/coreutils", + "@jupyterlab/csvviewer": "../../packages/csvviewer", + "@jupyterlab/csvviewer-extension": "../../packages/csvviewer-extension", + "@jupyterlab/debugger": "../../packages/debugger", + "@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", + "@jupyterlab/extensionmanager": "../../packages/extensionmanager", + "@jupyterlab/extensionmanager-extension": "../../packages/extensionmanager-extension", + "@jupyterlab/filebrowser": "../../packages/filebrowser", + "@jupyterlab/filebrowser-extension": "../../packages/filebrowser-extension", + "@jupyterlab/fileeditor": "../../packages/fileeditor", + "@jupyterlab/fileeditor-extension": "../../packages/fileeditor-extension", + "@jupyterlab/help-extension": "../../packages/help-extension", + "@jupyterlab/htmlviewer": "../../packages/htmlviewer", + "@jupyterlab/htmlviewer-extension": "../../packages/htmlviewer-extension", + "@jupyterlab/hub-extension": "../../packages/hub-extension", + "@jupyterlab/imageviewer": "../../packages/imageviewer", + "@jupyterlab/imageviewer-extension": "../../packages/imageviewer-extension", + "@jupyterlab/inspector": "../../packages/inspector", + "@jupyterlab/inspector-extension": "../../packages/inspector-extension", + "@jupyterlab/javascript-extension": "../../packages/javascript-extension", + "@jupyterlab/json-extension": "../../packages/json-extension", + "@jupyterlab/launcher": "../../packages/launcher", + "@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/markedparser-extension": "../../packages/markedparser-extension", + "@jupyterlab/mathjax2": "../../packages/mathjax2", + "@jupyterlab/mathjax2-extension": "../../packages/mathjax2-extension", + "@jupyterlab/metapackage": "../../packages/metapackage", + "@jupyterlab/nbconvert-css": "../../packages/nbconvert-css", + "@jupyterlab/nbformat": "../../packages/nbformat", + "@jupyterlab/notebook": "../../packages/notebook", + "@jupyterlab/notebook-extension": "../../packages/notebook-extension", + "@jupyterlab/observables": "../../packages/observables", + "@jupyterlab/outputarea": "../../packages/outputarea", + "@jupyterlab/pdf-extension": "../../packages/pdf-extension", + "@jupyterlab/property-inspector": "../../packages/property-inspector", + "@jupyterlab/rendermime": "../../packages/rendermime", + "@jupyterlab/rendermime-extension": "../../packages/rendermime-extension", + "@jupyterlab/rendermime-interfaces": "../../packages/rendermime-interfaces", + "@jupyterlab/running": "../../packages/running", + "@jupyterlab/running-extension": "../../packages/running-extension", + "@jupyterlab/services": "../../packages/services", + "@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/theme-dark-extension": "../../packages/theme-dark-extension", + "@jupyterlab/theme-light-extension": "../../packages/theme-light-extension", + "@jupyterlab/toc": "../../packages/toc", + "@jupyterlab/toc-extension": "../../packages/toc-extension", + "@jupyterlab/tooltip": "../../packages/tooltip", + "@jupyterlab/tooltip-extension": "../../packages/tooltip-extension", + "@jupyterlab/translation": "../../packages/translation", + "@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", + "@jupyterlab/template": "../../buildutils/template", + "@jupyterlab/galata": "../../galata", + "@jupyterlab/testutils": "../../testutils" + }, "staticDir": "../static" } } diff --git a/jupyterlab/staging/templates/403.html b/jupyterlab/staging/templates/403.html index 3155157..34a495a 100644 --- a/jupyterlab/staging/templates/403.html +++ b/jupyterlab/staging/templates/403.html @@ -1,3 +1,8 @@ + + diff --git a/jupyterlab/staging/templates/error.html b/jupyterlab/staging/templates/error.html index d2a9ba5..e5fa3df 100644 --- a/jupyterlab/staging/templates/error.html +++ b/jupyterlab/staging/templates/error.html @@ -28,7 +28,7 @@
    {% block h1_error %} -

    JupyterLab assets not detected, please rebuild

    +

    ElixirNote assets not detected, please rebuild

    diff --git a/jupyterlab/staging/templates/partial.html b/jupyterlab/staging/templates/partial.html index a3f368e..3c44af5 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 167557d..6d17d79 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 e319dfb..a6f3e46 100644 --- a/jupyterlab/staging/webpack.config.js +++ b/jupyterlab/staging/webpack.config.js @@ -1,9 +1,8 @@ // This file is auto-generated from the corresponding file in /dev_mode -// 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'); @@ -11,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; @@ -22,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 = [ diff --git a/jupyterlab/staging/webpack.prod.config.js b/jupyterlab/staging/webpack.prod.config.js index 4981339..bb8c9b3 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 c8d45a7..d7bfe89 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; diff --git a/jupyterlab/staging/webpack.prod.release.config.js b/jupyterlab/staging/webpack.prod.release.config.js index 54f6a38..060d39a 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 index cc7214f..4d780b2 100644 --- a/jupyterlab/staging/yarn.js +++ b/jupyterlab/staging/yarn.js @@ -65,7 +65,7 @@ module.exports = /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 549); +/******/ return __webpack_require__(__webpack_require__.s = 517); /******/ }) /************************************************************************/ /******/ ([ @@ -295,7 +295,7 @@ function __importDefault(mod) { exports.__esModule = true; -var _promise = __webpack_require__(227); +var _promise = __webpack_require__(224); var _promise2 = _interopRequireDefault(_promise); @@ -338,6 +338,12 @@ module.exports = require("util"); /***/ }), /* 4 */ +/***/ (function(module, exports) { + +module.exports = require("fs"); + +/***/ }), +/* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -1393,7 +1399,7 @@ exports.normalizeOS = normalizeOS; var _fs; function _load_fs() { - return _fs = _interopRequireDefault(__webpack_require__(5)); + return _fs = _interopRequireDefault(__webpack_require__(4)); } var _glob; @@ -1423,13 +1429,13 @@ function _load_blockingQueue() { var _promise; function _load_promise() { - return _promise = _interopRequireWildcard(__webpack_require__(50)); + return _promise = _interopRequireWildcard(__webpack_require__(51)); } var _promise2; function _load_promise2() { - return _promise2 = __webpack_require__(50); + return _promise2 = __webpack_require__(51); } var _map; @@ -1441,7 +1447,7 @@ function _load_map() { var _fsNormalized; function _load_fsNormalized() { - return _fsNormalized = __webpack_require__(218); + return _fsNormalized = __webpack_require__(216); } 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; } } @@ -1516,12 +1522,6 @@ function normalizeOS(body) { const cr = '\r'.charCodeAt(0); const lf = '\n'.charCodeAt(0); -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -module.exports = require("fs"); - /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { @@ -1565,7 +1565,13 @@ class ResponseError extends Error { } exports.ResponseError = ResponseError; -class OneTimePasswordError extends Error {} +class OneTimePasswordError extends Error { + constructor(notice) { + super(); + this.notice = notice; + } + +} exports.OneTimePasswordError = OneTimePasswordError; /***/ }), @@ -1580,7 +1586,7 @@ exports.OneTimePasswordError = OneTimePasswordError; /* 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_5__config__ = __webpack_require__(186); /* 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 */ @@ -1836,7 +1842,7 @@ const os = __webpack_require__(46); const path = __webpack_require__(0); const userHome = __webpack_require__(67).default; -var _require = __webpack_require__(225); +var _require = __webpack_require__(222); const getCacheDir = _require.getCacheDir, getConfigDir = _require.getConfigDir, @@ -2027,7 +2033,7 @@ module.exports = invariant; "use strict"; -var YAMLException = __webpack_require__(54); +var YAMLException = __webpack_require__(55); var TYPE_CONSTRUCTOR_OPTIONS = [ 'kind', @@ -2102,9 +2108,9 @@ module.exports = require("crypto"); /* 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_2__internal_symbol_observable__ = __webpack_require__(118); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(185); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(186); /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ @@ -2610,7 +2616,7 @@ exports.hyphenate = hyphenate; exports.camelCase = camelCase; exports.compareSortedArrays = compareSortedArrays; exports.sleep = sleep; -const _camelCase = __webpack_require__(230); +const _camelCase = __webpack_require__(227); function sortAlpha(a, b) { // sort alphabetically in a deterministic way @@ -2718,7 +2724,7 @@ function _load_asyncToGenerator() { var _parse; function _load_parse() { - return _parse = __webpack_require__(105); + return _parse = __webpack_require__(106); } Object.defineProperty(exports, 'parse', { @@ -2731,7 +2737,7 @@ Object.defineProperty(exports, 'parse', { var _stringify; function _load_stringify() { - return _stringify = __webpack_require__(199); + return _stringify = __webpack_require__(200); } Object.defineProperty(exports, 'stringify', { @@ -2758,7 +2764,7 @@ function _load_normalizePattern() { var _parse2; function _load_parse2() { - return _parse2 = _interopRequireDefault(__webpack_require__(105)); + return _parse2 = _interopRequireDefault(__webpack_require__(106)); } var _constants; @@ -2770,7 +2776,7 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -2812,7 +2818,7 @@ function implodeEntry(pattern, obj) { dependencies: blankObjectUndefined(obj.dependencies), optionalDependencies: blankObjectUndefined(obj.optionalDependencies), permissions: blankObjectUndefined(obj.permissions), - prebuilt2Variants: blankObjectUndefined(obj.prebuilt2Variants) + prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants) }; if (integrity) { imploded.integrity = integrity; @@ -2975,7 +2981,7 @@ class Lockfile { peerDependencies: pkg.peerDependencies, optionalDependencies: pkg.optionalDependencies, permissions: ref.permissions, - prebuilt2Variants: pkg.prebuilt2Variants + prebuiltVariants: pkg.prebuiltVariants }); lockfile[pattern] = obj; @@ -2994,29 +3000,12 @@ 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 _assign = __webpack_require__(559); var _assign2 = _interopRequireDefault(_assign); @@ -3036,6 +3025,23 @@ exports.default = _assign2.default || function (target) { return target; }; +/***/ }), +/* 21 */ +/***/ (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; + + /***/ }), /* 22 */ /***/ (function(module, exports) { @@ -4362,7 +4368,7 @@ function coerce(version) { if (match == null) return null; - return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); + return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); } @@ -4387,7 +4393,7 @@ module.exports = require("url"); /* 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_3__util_tryCatch__ = __webpack_require__(57); /* 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 */ @@ -4954,7 +4960,7 @@ 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['ssh-private'] = __webpack_require__(193); formats['openssh'] = formats['ssh-private']; formats['dnssec'] = __webpack_require__(326); @@ -5255,11 +5261,11 @@ function nullify(obj = {}) { "use strict"; -const escapeStringRegexp = __webpack_require__(388); -const ansiStyles = __webpack_require__(506); -const stdoutColor = __webpack_require__(598).stdout; +const escapeStringRegexp = __webpack_require__(382); +const ansiStyles = __webpack_require__(474); +const stdoutColor = __webpack_require__(566).stdout; -const template = __webpack_require__(599); +const template = __webpack_require__(567); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -5707,7 +5713,7 @@ 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['ssh-private'] = __webpack_require__(193); formats['openssh'] = formats['ssh-private']; formats['ssh'] = formats['ssh-private']; formats['dnssec'] = __webpack_require__(326); @@ -5940,7 +5946,7 @@ exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefi var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -6041,13 +6047,13 @@ function _load_objectPath() { var _hooks; function _load_hooks() { - return _hooks = __webpack_require__(374); + return _hooks = __webpack_require__(368); } var _index; function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(220)); + return _index = _interopRequireDefault(__webpack_require__(218)); } var _errors; @@ -6059,7 +6065,7 @@ function _load_errors() { var _integrityChecker; function _load_integrityChecker() { - return _integrityChecker = _interopRequireDefault(__webpack_require__(208)); + return _integrityChecker = _interopRequireDefault(__webpack_require__(206)); } var _lockfile; @@ -6077,37 +6083,37 @@ function _load_lockfile2() { var _packageFetcher; function _load_packageFetcher() { - return _packageFetcher = _interopRequireWildcard(__webpack_require__(210)); + return _packageFetcher = _interopRequireWildcard(__webpack_require__(208)); } var _packageInstallScripts; function _load_packageInstallScripts() { - return _packageInstallScripts = _interopRequireDefault(__webpack_require__(557)); + return _packageInstallScripts = _interopRequireDefault(__webpack_require__(525)); } var _packageCompatibility; function _load_packageCompatibility() { - return _packageCompatibility = _interopRequireWildcard(__webpack_require__(209)); + return _packageCompatibility = _interopRequireWildcard(__webpack_require__(207)); } var _packageResolver; function _load_packageResolver() { - return _packageResolver = _interopRequireDefault(__webpack_require__(366)); + return _packageResolver = _interopRequireDefault(__webpack_require__(360)); } var _packageLinker; function _load_packageLinker() { - return _packageLinker = _interopRequireDefault(__webpack_require__(211)); + return _packageLinker = _interopRequireDefault(__webpack_require__(209)); } var _index2; function _load_index2() { - return _index2 = __webpack_require__(57); + return _index2 = __webpack_require__(58); } var _index3; @@ -6119,7 +6125,7 @@ function _load_index3() { var _autoclean; function _load_autoclean() { - return _autoclean = __webpack_require__(354); + return _autoclean = __webpack_require__(348); } var _constants; @@ -6137,7 +6143,7 @@ function _load_normalizePattern() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _map; @@ -6149,13 +6155,13 @@ function _load_map() { var _yarnVersion; function _load_yarnVersion() { - return _yarnVersion = __webpack_require__(120); + return _yarnVersion = __webpack_require__(105); } var _generatePnpMap; function _load_generatePnpMap() { - return _generatePnpMap = __webpack_require__(579); + return _generatePnpMap = __webpack_require__(547); } var _workspaceLayout; @@ -6167,7 +6173,7 @@ function _load_workspaceLayout() { var _resolutionMap; function _load_resolutionMap() { - return _resolutionMap = _interopRequireDefault(__webpack_require__(214)); + return _resolutionMap = _interopRequireDefault(__webpack_require__(212)); } var _guessName; @@ -6179,20 +6185,20 @@ function _load_guessName() { var _audit; function _load_audit() { - return _audit = _interopRequireDefault(__webpack_require__(353)); + return _audit = _interopRequireDefault(__webpack_require__(347)); } 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 deepEqual = __webpack_require__(599); 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 uuid = __webpack_require__(120); const ssri = __webpack_require__(65); const ONE_DAY = 1000 * 60 * 60 * 24; @@ -7232,9 +7238,9 @@ class Install { 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)) { + // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages + const hasPrebuiltPackage = file.relative.startsWith('prebuilt/'); + if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) { yield (_fs || _load_fs()).unlink(file.absolute); } } @@ -7285,7 +7291,7 @@ class Install { }); 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); + return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants); }); const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; @@ -7485,7 +7491,7 @@ function setFlags(commander) { /* 35 */ /***/ (function(module, exports, __webpack_require__) { -var isObject = __webpack_require__(52); +var isObject = __webpack_require__(53); module.exports = function (it) { if (!isObject(it)) throw TypeError(it + ' is not an object!'); return it; @@ -7504,7 +7510,7 @@ module.exports = function (it) { /* 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_4__util_ObjectUnsubscribedError__ = __webpack_require__(190); /* 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 */ @@ -24882,7 +24888,7 @@ var isArray = Array.isArray || (function (x) { return x && typeof x.length === ' var dP = __webpack_require__(72); var createDesc = __webpack_require__(132); -module.exports = __webpack_require__(51) ? function (object, key, value) { +module.exports = __webpack_require__(52) ? function (object, key, value) { return dP.f(object, key, createDesc(1, value)); } : function (object, key, value) { object[key] = value; @@ -24966,7 +24972,7 @@ module.exports.extend = extend; /*eslint-disable max-len*/ var common = __webpack_require__(43); -var YAMLException = __webpack_require__(54); +var YAMLException = __webpack_require__(55); var Type = __webpack_require__(10); @@ -25232,6 +25238,223 @@ function isScheduler(value) { "use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.exec = exports.queue = undefined; +exports.forkp = forkp; +exports.spawnp = spawnp; +exports.forwardSignalToSpawnedProcesses = forwardSignalToSpawnedProcesses; +exports.spawn = spawn; + +var _constants; + +function _load_constants() { + return _constants = _interopRequireWildcard(__webpack_require__(8)); +} + +var _blockingQueue; + +function _load_blockingQueue() { + return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); +} + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); +} + +var _promise; + +function _load_promise() { + return _promise = __webpack_require__(51); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +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; } } + +/* global child_process$spawnOpts */ + +const child = __webpack_require__(331); +const fs = __webpack_require__(4); +const path = __webpack_require__(0); + +const queue = exports.queue = new (_blockingQueue || _load_blockingQueue()).default('child', (_constants || _load_constants()).CHILD_CONCURRENCY); + +// TODO: this uid check is kinda whack +let uid = 0; + +const exec = exports.exec = (0, (_promise || _load_promise()).promisify)(child.exec); + +function validate(program, opts = {}) { + if (program.match(/[\\\/]/)) { + return; + } + + if (process.platform === 'win32' && process.env.PATHEXT) { + const cwd = opts.cwd || process.cwd(); + const pathext = process.env.PATHEXT; + + for (var _iterator = pathext.split(';'), _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 ext = _ref; + + const candidate = path.join(cwd, `${program}${ext}`); + if (fs.existsSync(candidate)) { + throw new Error(`Potentially dangerous call to "${program}" in ${cwd}`); + } + } + } +} + +function forkp(program, args, opts) { + validate(program, opts); + const key = String(++uid); + return new Promise((resolve, reject) => { + const proc = child.fork(program, args, opts); + spawnedProcesses[key] = proc; + + proc.on('error', error => { + reject(error); + }); + + proc.on('close', exitCode => { + resolve(exitCode); + }); + }); +} + +function spawnp(program, args, opts) { + validate(program, opts); + const key = String(++uid); + return new Promise((resolve, reject) => { + const proc = child.spawn(program, args, opts); + spawnedProcesses[key] = proc; + + proc.on('error', error => { + reject(error); + }); + + proc.on('close', exitCode => { + resolve(exitCode); + }); + }); +} + +const spawnedProcesses = {}; + +function forwardSignalToSpawnedProcesses(signal) { + for (var _iterator2 = Object.keys(spawnedProcesses), _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 key = _ref2; + + spawnedProcesses[key].kill(signal); + } +} + +function spawn(program, args, opts = {}, onData) { + const key = opts.cwd || String(++uid); + return queue.push(key, () => new Promise((resolve, reject) => { + validate(program, opts); + + const proc = child.spawn(program, args, opts); + spawnedProcesses[key] = proc; + + let processingDone = false; + let processClosed = false; + let err = null; + + let stdout = ''; + + proc.on('error', err => { + if (err.code === 'ENOENT') { + reject(new (_errors || _load_errors()).ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program)); + } else { + reject(err); + } + }); + + function updateStdout(chunk) { + stdout += chunk; + if (onData) { + onData(chunk); + } + } + + function finish() { + delete spawnedProcesses[key]; + if (err) { + reject(err); + } else { + resolve(stdout.trim()); + } + } + + if (typeof opts.process === 'function') { + opts.process(proc, updateStdout, reject, function () { + if (processClosed) { + finish(); + } else { + processingDone = true; + } + }); + } else { + if (proc.stderr) { + proc.stderr.on('data', updateStdout); + } + + if (proc.stdout) { + proc.stdout.on('data', updateStdout); + } + + processingDone = true; + } + + proc.on('close', (code, signal) => { + if (signal || code >= 1) { + err = new (_errors || _load_errors()).ProcessTermError(['Command failed.', signal ? `Exit signal: ${signal}` : `Exit code: ${code}`, `Command: ${program}`, `Arguments: ${args.join(' ')}`, `Directory: ${opts.cwd || process.cwd()}`, `Output:\n${stdout.trim()}`].join('\n')); + err.EXIT_SIGNAL = signal; + err.EXIT_CODE = code; + } + + if (processingDone || err) { + finish(); + } else { + processClosed = true; + } + }); + })); +} + +/***/ }), +/* 51 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + Object.defineProperty(exports, "__esModule", { value: true }); @@ -25309,7 +25532,7 @@ function queue(arr, promiseProducer, concurrency = Infinity) { } /***/ }), -/* 51 */ +/* 52 */ /***/ (function(module, exports, __webpack_require__) { // Thank's IE8 for his funny defineProperty @@ -25319,7 +25542,7 @@ module.exports = !__webpack_require__(112)(function () { /***/ }), -/* 52 */ +/* 53 */ /***/ (function(module, exports) { module.exports = function (it) { @@ -25328,14 +25551,14 @@ module.exports = function (it) { /***/ }), -/* 53 */ +/* 54 */ /***/ (function(module, exports) { module.exports = {}; /***/ }), -/* 54 */ +/* 55 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25385,7 +25608,7 @@ module.exports = YAMLException; /***/ }), -/* 55 */ +/* 56 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25420,7 +25643,7 @@ module.exports = new Schema({ /***/ }), -/* 56 */ +/* 57 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -25446,7 +25669,7 @@ function tryCatch(fn) { /***/ }), -/* 57 */ +/* 58 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25460,7 +25683,7 @@ exports.registryNames = exports.registries = undefined; var _yarnRegistry; function _load_yarnRegistry() { - return _yarnRegistry = _interopRequireDefault(__webpack_require__(559)); + return _yarnRegistry = _interopRequireDefault(__webpack_require__(527)); } var _npmRegistry; @@ -25478,182 +25701,6 @@ const registries = exports.registries = { const registryNames = exports.registryNames = Object.keys(registries); -/***/ }), -/* 58 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.exec = exports.queue = undefined; -exports.forkp = forkp; -exports.spawnp = spawnp; -exports.forwardSignalToSpawnedProcesses = forwardSignalToSpawnedProcesses; -exports.spawn = spawn; - -var _constants; - -function _load_constants() { - return _constants = _interopRequireWildcard(__webpack_require__(8)); -} - -var _blockingQueue; - -function _load_blockingQueue() { - return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); -} - -var _errors; - -function _load_errors() { - return _errors = __webpack_require__(6); -} - -var _promise; - -function _load_promise() { - return _promise = __webpack_require__(50); -} - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -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; } } - -/* global child_process$spawnOpts */ - -const child = __webpack_require__(331); - -const queue = exports.queue = new (_blockingQueue || _load_blockingQueue()).default('child', (_constants || _load_constants()).CHILD_CONCURRENCY); - -// TODO: this uid check is kinda whack -let uid = 0; - -const exec = exports.exec = (0, (_promise || _load_promise()).promisify)(child.exec); - -function forkp(program, args, opts) { - return new Promise((resolve, reject) => { - const proc = child.fork(program, args, opts); - - proc.on('error', error => { - reject(error); - }); - - proc.on('close', exitCode => { - resolve(exitCode); - }); - }); -} - -function spawnp(program, args, opts) { - return new Promise((resolve, reject) => { - const proc = child.spawn(program, args, opts); - - proc.on('error', error => { - reject(error); - }); - - proc.on('close', exitCode => { - resolve(exitCode); - }); - }); -} - -const spawnedProcesses = {}; - -function forwardSignalToSpawnedProcesses(signal) { - for (var _iterator = Object.keys(spawnedProcesses), _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 key = _ref; - - spawnedProcesses[key].kill(signal); - } -} - -function spawn(program, args, opts = {}, onData) { - const key = opts.cwd || String(++uid); - return queue.push(key, () => new Promise((resolve, reject) => { - const proc = child.spawn(program, args, opts); - spawnedProcesses[key] = proc; - - let processingDone = false; - let processClosed = false; - let err = null; - - let stdout = ''; - - proc.on('error', err => { - if (err.code === 'ENOENT') { - reject(new (_errors || _load_errors()).ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program)); - } else { - reject(err); - } - }); - - function updateStdout(chunk) { - stdout += chunk; - if (onData) { - onData(chunk); - } - } - - function finish() { - delete spawnedProcesses[key]; - if (err) { - reject(err); - } else { - resolve(stdout.trim()); - } - } - - if (typeof opts.process === 'function') { - opts.process(proc, updateStdout, reject, function () { - if (processClosed) { - finish(); - } else { - processingDone = true; - } - }); - } else { - if (proc.stderr) { - proc.stderr.on('data', updateStdout); - } - - if (proc.stdout) { - proc.stdout.on('data', updateStdout); - } - - processingDone = true; - } - - proc.on('close', (code, signal) => { - if (signal || code >= 1) { - err = new (_errors || _load_errors()).ProcessTermError(['Command failed.', signal ? `Exit signal: ${signal}` : `Exit code: ${code}`, `Command: ${program}`, `Arguments: ${args.join(' ')}`, `Directory: ${opts.cwd || process.cwd()}`, `Output:\n${stdout.trim()}`].join('\n')); - err.EXIT_SIGNAL = signal; - err.EXIT_CODE = code; - } - - if (processingDone || err) { - finish(); - } else { - processClosed = true; - } - }); - })); -} - /***/ }), /* 59 */ /***/ (function(module, exports, __webpack_require__) { @@ -25980,7 +26027,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return __WEBPACK_IMPORTED_MODULE_47__internal_operators_mergeScan__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_48__internal_operators_min__ = __webpack_require__(875); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return __WEBPACK_IMPORTED_MODULE_48__internal_operators_min__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_49__internal_operators_multicast__ = __webpack_require__(116); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_49__internal_operators_multicast__ = __webpack_require__(117); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return __WEBPACK_IMPORTED_MODULE_49__internal_operators_multicast__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_50__internal_operators_observeOn__ = __webpack_require__(434); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return __WEBPACK_IMPORTED_MODULE_50__internal_operators_observeOn__["b"]; }); @@ -26002,7 +26049,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return __WEBPACK_IMPORTED_MODULE_58__internal_operators_publishReplay__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_59__internal_operators_race__ = __webpack_require__(884); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "race", function() { return __WEBPACK_IMPORTED_MODULE_59__internal_operators_race__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_60__internal_operators_reduce__ = __webpack_require__(187); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_60__internal_operators_reduce__ = __webpack_require__(188); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return __WEBPACK_IMPORTED_MODULE_60__internal_operators_reduce__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_61__internal_operators_repeat__ = __webpack_require__(885); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return __WEBPACK_IMPORTED_MODULE_61__internal_operators_repeat__["a"]; }); @@ -26060,7 +26107,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return __WEBPACK_IMPORTED_MODULE_87__internal_operators_throttle__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_88__internal_operators_throttleTime__ = __webpack_require__(905); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return __WEBPACK_IMPORTED_MODULE_88__internal_operators_throttleTime__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_89__internal_operators_throwIfEmpty__ = __webpack_require__(188); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_89__internal_operators_throwIfEmpty__ = __webpack_require__(189); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return __WEBPACK_IMPORTED_MODULE_89__internal_operators_throwIfEmpty__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_90__internal_operators_timeInterval__ = __webpack_require__(906); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return __WEBPACK_IMPORTED_MODULE_90__internal_operators_timeInterval__["a"]; }); @@ -26597,7 +26644,7 @@ function getPrioritizedHash (algo1, algo2) { // If you have no idea what ASN.1 or BER is, see this: // ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc -var Ber = __webpack_require__(514); +var Ber = __webpack_require__(482); @@ -26629,7 +26676,7 @@ exports.home = undefined; var _rootUser; function _load_rootUser() { - return _rootUser = _interopRequireDefault(__webpack_require__(223)); + return _rootUser = _interopRequireDefault(__webpack_require__(221)); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -26704,11 +26751,11 @@ module.exports = function (it, key) { /***/ (function(module, exports, __webpack_require__) { var anObject = __webpack_require__(35); -var IE8_DOM_DEFINE = __webpack_require__(238); -var toPrimitive = __webpack_require__(255); +var IE8_DOM_DEFINE = __webpack_require__(235); +var toPrimitive = __webpack_require__(252); var dP = Object.defineProperty; -exports.f = __webpack_require__(51) ? Object.defineProperty : function defineProperty(O, P, Attributes) { +exports.f = __webpack_require__(52) ? Object.defineProperty : function defineProperty(O, P, Attributes) { anObject(O); P = toPrimitive(P, true); anObject(Attributes); @@ -26743,7 +26790,7 @@ var Schema = __webpack_require__(44); module.exports = Schema.DEFAULT = new Schema({ include: [ - __webpack_require__(55) + __webpack_require__(56) ], explicit: [ __webpack_require__(290), @@ -29586,13 +29633,13 @@ function _load_baseResolver() { var _npmResolver; function _load_npmResolver() { - return _npmResolver = _interopRequireDefault(__webpack_require__(217)); + return _npmResolver = _interopRequireDefault(__webpack_require__(215)); } var _yarnResolver; function _load_yarnResolver() { - return _yarnResolver = _interopRequireDefault(__webpack_require__(576)); + return _yarnResolver = _interopRequireDefault(__webpack_require__(544)); } var _gitResolver; @@ -29604,43 +29651,43 @@ function _load_gitResolver() { var _tarballResolver; function _load_tarballResolver() { - return _tarballResolver = _interopRequireDefault(__webpack_require__(574)); + return _tarballResolver = _interopRequireDefault(__webpack_require__(542)); } var _githubResolver; function _load_githubResolver() { - return _githubResolver = _interopRequireDefault(__webpack_require__(367)); + return _githubResolver = _interopRequireDefault(__webpack_require__(361)); } var _fileResolver; function _load_fileResolver() { - return _fileResolver = _interopRequireDefault(__webpack_require__(215)); + return _fileResolver = _interopRequireDefault(__webpack_require__(213)); } var _linkResolver; function _load_linkResolver() { - return _linkResolver = _interopRequireDefault(__webpack_require__(368)); + return _linkResolver = _interopRequireDefault(__webpack_require__(362)); } var _gitlabResolver; function _load_gitlabResolver() { - return _gitlabResolver = _interopRequireDefault(__webpack_require__(572)); + return _gitlabResolver = _interopRequireDefault(__webpack_require__(540)); } var _gistResolver; function _load_gistResolver() { - return _gistResolver = _interopRequireDefault(__webpack_require__(216)); + return _gistResolver = _interopRequireDefault(__webpack_require__(214)); } var _bitbucketResolver; function _load_bitbucketResolver() { - return _bitbucketResolver = _interopRequireDefault(__webpack_require__(571)); + return _bitbucketResolver = _interopRequireDefault(__webpack_require__(539)); } var _hostedGitResolver; @@ -29652,7 +29699,7 @@ function _load_hostedGitResolver() { var _registryResolver; function _load_registryResolver() { - return _registryResolver = _interopRequireDefault(__webpack_require__(573)); + return _registryResolver = _interopRequireDefault(__webpack_require__(541)); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -29730,7 +29777,7 @@ for (const key in registries) { var _ = __webpack_require__(38); var chalk = __webpack_require__(30); -var runAsync = __webpack_require__(181); +var runAsync = __webpack_require__(182); var { filter, flatMap, share, take, takeUntil } = __webpack_require__(63); var Choices = __webpack_require__(686); var ScreenManager = __webpack_require__(697); @@ -29878,7 +29925,7 @@ module.exports = Prompt; "use strict"; -var { fromEvent } = __webpack_require__(182); +var { fromEvent } = __webpack_require__(183); var { filter, map, share } = __webpack_require__(63); function normalizeKeypressEvents(value, key) { @@ -31308,7 +31355,7 @@ try { } catch (er) {} var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} -var expand = __webpack_require__(229) +var expand = __webpack_require__(226) var plTypes = { '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, @@ -32370,7 +32417,7 @@ var PrivateKey = __webpack_require__(33); var pkcs1 = __webpack_require__(327); var pkcs8 = __webpack_require__(157); -var sshpriv = __webpack_require__(192); +var sshpriv = __webpack_require__(193); var rfc4253 = __webpack_require__(103); var errors = __webpack_require__(74); @@ -32567,7 +32614,7 @@ exports.SCOPE_SEPARATOR = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -32585,25 +32632,25 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _npmResolver; function _load_npmResolver() { - return _npmResolver = _interopRequireDefault(__webpack_require__(217)); + return _npmResolver = _interopRequireDefault(__webpack_require__(215)); } var _envReplace; function _load_envReplace() { - return _envReplace = _interopRequireDefault(__webpack_require__(577)); + return _envReplace = _interopRequireDefault(__webpack_require__(545)); } var _baseRegistry; function _load_baseRegistry() { - return _baseRegistry = _interopRequireDefault(__webpack_require__(558)); + return _baseRegistry = _interopRequireDefault(__webpack_require__(526)); } var _misc; @@ -32615,7 +32662,7 @@ function _load_misc() { var _path; function _load_path() { - return _path = __webpack_require__(377); + return _path = __webpack_require__(371); } var _normalizeUrl; @@ -32751,7 +32798,7 @@ class NpmRegistry extends (_baseRegistry || _load_baseRegistry()).default { let resolved = pathname; if (!REGEX_REGISTRY_PREFIX.test(pathname)) { - resolved = (_url || _load_url()).default.resolve((0, (_misc || _load_misc()).addSuffix)(registry, '/'), pathname); + resolved = (_url || _load_url()).default.resolve((0, (_misc || _load_misc()).addSuffix)(registry, '/'), `./${pathname}`); } if (REGEX_REGISTRY_ENFORCED_HTTPS.test(resolved)) { @@ -32826,6 +32873,10 @@ class NpmRegistry extends (_baseRegistry || _load_baseRegistry()).default { } _this.reporter.info(_this.reporter.lang('twoFactorAuthenticationEnabled')); + if (error.notice) { + _this.reporter.info(error.notice); + } + _this.otp = yield (0, (_login || _load_login()).getOneTimePassword)(_this.reporter); _this.requestManager.clearCache(); @@ -33225,7 +33276,7 @@ module.exports = function (it) { /* 92 */ /***/ (function(module, exports, __webpack_require__) { -var isObject = __webpack_require__(52); +var isObject = __webpack_require__(53); var document = __webpack_require__(17).document; // typeof document.createElement is 'object' in old IE var is = isObject(document) && isObject(document.createElement); @@ -33272,7 +33323,7 @@ module.exports.f = function (C) { var def = __webpack_require__(72).f; var has = __webpack_require__(71); -var TAG = __webpack_require__(20)('toStringTag'); +var TAG = __webpack_require__(21)('toStringTag'); module.exports = function (it, tag, stat) { if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag }); @@ -33307,7 +33358,7 @@ module.exports = function (it) { /***/ (function(module, exports, __webpack_require__) { // to indexed object, toObject with fallback for non-array-like ES3 strings -var IObject = __webpack_require__(170); +var IObject = __webpack_require__(171); var defined = __webpack_require__(91); module.exports = function (it) { return IObject(defined(it)); @@ -33360,7 +33411,7 @@ module.exports = function (it) { module.exports = glob -var fs = __webpack_require__(5) +var fs = __webpack_require__(4) var rp = __webpack_require__(140) var minimatch = __webpack_require__(82) var Minimatch = minimatch.Minimatch @@ -33369,7 +33420,7 @@ var EE = __webpack_require__(77).EventEmitter var path = __webpack_require__(0) var assert = __webpack_require__(28) var isAbsolute = __webpack_require__(101) -var globSync = __webpack_require__(272) +var globSync = __webpack_require__(269) var common = __webpack_require__(141) var alphasort = common.alphasort var alphasorti = common.alphasorti @@ -34180,7 +34231,7 @@ if (process.env.READABLE_STREAM === 'disable' && Stream) { exports.Stream = Stream || exports; exports.Readable = exports; exports.Writable = __webpack_require__(408); - exports.Duplex = __webpack_require__(115); + exports.Duplex = __webpack_require__(116); exports.Transform = __webpack_require__(407); exports.PassThrough = __webpack_require__(792); } @@ -34371,6 +34422,85 @@ module.exports = require("tty"); "use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getInstallationMethod = exports.version = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let getInstallationMethod = exports.getInstallationMethod = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + let installationMethod = originalInstallationMethod; + + // If there's a package.json in the parent directory, it could have an + // override for the installation method, so we should prefer that over + // whatever was originally in Yarn's package.json. This is the case with + // systems such as Homebrew, which take the tarball and modify the + // installation method so we're aware of the fact that Yarn was installed via + // Homebrew (so things like update notifications can point out the correct + // command to upgrade). + try { + const manifestPath = (_path || _load_path()).default.join(__dirname, '..', 'package.json'); + if ((_fs2 || _load_fs2()).default.existsSync(manifestPath)) { + // non-async version is deprecated + const manifest = yield (0, (_fs || _load_fs()).readJson)(manifestPath); + if (manifest.installationMethod) { + installationMethod = manifest.installationMethod; + } + } + } catch (e) { + // Ignore any errors; this is not critical functionality. + } + return installationMethod; + }); + + return function getInstallationMethod() { + return _ref.apply(this, arguments); + }; +})(); + +var _fs; + +function _load_fs() { + return _fs = __webpack_require__(5); +} + +var _fs2; + +function _load_fs2() { + return _fs2 = _interopRequireDefault(__webpack_require__(4)); +} + +var _path; + +function _load_path() { + return _path = _interopRequireDefault(__webpack_require__(0)); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// This will be bundled directly in the .js file for production builds +var _require = __webpack_require__(195); /** + * Determines the current version of Yarn itself. + * + */ + +const version = _require.version, + originalInstallationMethod = _require.installationMethod; +exports.version = version; + +/***/ }), +/* 106 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + Object.defineProperty(exports, "__esModule", { value: true }); @@ -34805,15 +34935,27 @@ function hasMergeConflicts(str) { function parse(str, fileLoc) { const parser = new Parser(str, fileLoc); parser.next(); - try { - return parser.parse(); - } catch (error1) { + + if (!fileLoc.endsWith(`.yml`)) { try { - return safeLoad(str, { - schema: FAILSAFE_SCHEMA - }); - } catch (error2) { - throw error1; + return parser.parse(); + } catch (error1) { + try { + return safeLoad(str, { + schema: FAILSAFE_SCHEMA + }); + } catch (error2) { + throw error1; + } + } + } else { + const result = safeLoad(str, { + schema: FAILSAFE_SCHEMA + }); + if (typeof result === 'object') { + return result; + } else { + return {}; } } } @@ -34834,280 +34976,6 @@ function parseWithConflict(str, fileLoc) { } } -/***/ }), -/* 106 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - - -module.exports = { - copy: copy, - checkDataType: checkDataType, - checkDataTypes: checkDataTypes, - coerceToTypes: coerceToTypes, - toHash: toHash, - getProperty: getProperty, - escapeQuotes: escapeQuotes, - equal: __webpack_require__(204), - ucs2length: __webpack_require__(480), - varOccurences: varOccurences, - varReplace: varReplace, - cleanUpCode: cleanUpCode, - finalCleanUpCode: finalCleanUpCode, - schemaHasRules: schemaHasRules, - schemaHasRulesExcept: schemaHasRulesExcept, - toQuotedString: toQuotedString, - getPathExpr: getPathExpr, - getPath: getPath, - getData: getData, - unescapeFragment: unescapeFragment, - unescapeJsonPointer: unescapeJsonPointer, - escapeFragment: escapeFragment, - escapeJsonPointer: escapeJsonPointer -}; - - -function copy(o, to) { - to = to || {}; - for (var key in o) to[key] = o[key]; - return to; -} - - -function checkDataType(dataType, data, negate) { - var EQUAL = negate ? ' !== ' : ' === ' - , AND = negate ? ' || ' : ' && ' - , OK = negate ? '!' : '' - , NOT = negate ? '' : '!'; - switch (dataType) { - case 'null': return data + EQUAL + 'null'; - case 'array': return OK + 'Array.isArray(' + data + ')'; - case 'object': return '(' + OK + data + AND + - 'typeof ' + data + EQUAL + '"object"' + AND + - NOT + 'Array.isArray(' + data + '))'; - case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND + - NOT + '(' + data + ' % 1)' + - AND + data + EQUAL + data + ')'; - default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; - } -} - - -function checkDataTypes(dataTypes, data) { - switch (dataTypes.length) { - case 1: return checkDataType(dataTypes[0], data, true); - default: - var code = ''; - var types = toHash(dataTypes); - if (types.array && types.object) { - code = types.null ? '(': '(!' + data + ' || '; - code += 'typeof ' + data + ' !== "object")'; - delete types.null; - delete types.array; - delete types.object; - } - if (types.number) delete types.integer; - for (var t in types) - code += (code ? ' && ' : '' ) + checkDataType(t, data, true); - - return code; - } -} - - -var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]); -function coerceToTypes(optionCoerceTypes, dataTypes) { - if (Array.isArray(dataTypes)) { - var types = []; - for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); - return paths[lvl - up]; - } - - if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); - data = 'data' + ((lvl - up) || ''); - if (!jsonPointer) return data; - } - - var expr = data; - var segments = jsonPointer.split('/'); - for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); + return paths[lvl - up]; + } + + if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); + data = 'data' + ((lvl - up) || ''); + if (!jsonPointer) return data; + } + + var expr = data; + var segments = jsonPointer.split('/'); + for (var i=0; i * @@ -37102,7 +37244,7 @@ module.exports = micromatch; /***/ }), -/* 115 */ +/* 116 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -37136,7 +37278,7 @@ module.exports = micromatch; /**/ -var pna = __webpack_require__(180); +var pna = __webpack_require__(181); /**/ /**/ @@ -37239,7 +37381,7 @@ Duplex.prototype._destroy = function (err, cb) { }; /***/ }), -/* 116 */ +/* 117 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -37287,7 +37429,7 @@ var MulticastOperator = /*@__PURE__*/ (function () { /***/ }), -/* 117 */ +/* 118 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -37298,7 +37440,7 @@ var observable = typeof Symbol === 'function' && Symbol.observable || '@@observa /***/ }), -/* 118 */ +/* 119 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -37311,7 +37453,7 @@ function identity(x) { /***/ }), -/* 119 */ +/* 120 */ /***/ (function(module, exports, __webpack_require__) { var v1 = __webpack_require__(957); @@ -37324,85 +37466,6 @@ uuid.v4 = v4; module.exports = uuid; -/***/ }), -/* 120 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getInstallationMethod = exports.version = undefined; - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -let getInstallationMethod = exports.getInstallationMethod = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - let installationMethod = originalInstallationMethod; - - // If there's a package.json in the parent directory, it could have an - // override for the installation method, so we should prefer that over - // whatever was originally in Yarn's package.json. This is the case with - // systems such as Homebrew, which take the tarball and modify the - // installation method so we're aware of the fact that Yarn was installed via - // Homebrew (so things like update notifications can point out the correct - // command to upgrade). - try { - const manifestPath = (_path || _load_path()).default.join(__dirname, '..', 'package.json'); - if ((_fs2 || _load_fs2()).default.existsSync(manifestPath)) { - // non-async version is deprecated - const manifest = yield (0, (_fs || _load_fs()).readJson)(manifestPath); - if (manifest.installationMethod) { - installationMethod = manifest.installationMethod; - } - } - } catch (e) { - // Ignore any errors; this is not critical functionality. - } - return installationMethod; - }); - - return function getInstallationMethod() { - return _ref.apply(this, arguments); - }; -})(); - -var _fs; - -function _load_fs() { - return _fs = __webpack_require__(4); -} - -var _fs2; - -function _load_fs2() { - return _fs2 = _interopRequireDefault(__webpack_require__(5)); -} - -var _path; - -function _load_path() { - return _path = _interopRequireDefault(__webpack_require__(0)); -} - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -// This will be bundled directly in the .js file for production builds -var _require = __webpack_require__(194); /** - * Determines the current version of Yarn itself. - * - */ - -const version = _require.version, - originalInstallationMethod = _require.installationMethod; -exports.version = version; - /***/ }), /* 121 */ /***/ (function(module, exports, __webpack_require__) { @@ -37695,7 +37758,7 @@ function _load_errors() { var _index; function _load_index() { - return _index = __webpack_require__(57); + return _index = __webpack_require__(58); } var _baseReporter; @@ -37731,25 +37794,25 @@ function _load_add() { var _remove; function _load_remove() { - return _remove = __webpack_require__(359); + return _remove = __webpack_require__(353); } var _upgrade; function _load_upgrade() { - return _upgrade = __webpack_require__(207); + return _upgrade = __webpack_require__(205); } var _upgradeInteractive; function _load_upgradeInteractive() { - return _upgradeInteractive = __webpack_require__(362); + return _upgradeInteractive = __webpack_require__(356); } var _packageLinker; function _load_packageLinker() { - return _packageLinker = __webpack_require__(211); + return _packageLinker = __webpack_require__(209); } var _constants; @@ -37761,7 +37824,7 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -37969,7 +38032,7 @@ function _load_lockfile() { var _packageReference; function _load_packageReference() { - return _packageReference = _interopRequireDefault(__webpack_require__(365)); + return _packageReference = _interopRequireDefault(__webpack_require__(359)); } var _index; @@ -37993,19 +38056,19 @@ function _load_constants() { var _version; function _load_version() { - return _version = _interopRequireWildcard(__webpack_require__(226)); + return _version = _interopRequireWildcard(__webpack_require__(223)); } var _workspaceResolver; function _load_workspaceResolver() { - return _workspaceResolver = _interopRequireDefault(__webpack_require__(570)); + return _workspaceResolver = _interopRequireDefault(__webpack_require__(538)); } var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _normalizePattern4; @@ -38018,7 +38081,7 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -const micromatch = __webpack_require__(114); +const micromatch = __webpack_require__(115); class PackageRequest { constructor(req, resolver) { @@ -38064,7 +38127,7 @@ class PackageRequest { }, optionalDependencies: shrunk.optionalDependencies || {}, dependencies: shrunk.dependencies || {}, - prebuilt2Variants: shrunk.prebuilt2Variants || {} + prebuiltVariants: shrunk.prebuiltVariants || {} }; } else { return null; @@ -38565,7 +38628,7 @@ function _load_misc() { var _version; function _load_version() { - return _version = _interopRequireWildcard(__webpack_require__(226)); + return _version = _interopRequireWildcard(__webpack_require__(223)); } var _guessName; @@ -38577,7 +38640,7 @@ function _load_guessName() { var _index2; function _load_index2() { - return _index2 = __webpack_require__(57); + return _index2 = __webpack_require__(58); } var _exoticResolver; @@ -38589,7 +38652,7 @@ function _load_exoticResolver() { var _git; function _load_git() { - return _git = _interopRequireDefault(__webpack_require__(219)); + return _git = _interopRequireDefault(__webpack_require__(217)); } 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; } } @@ -38846,13 +38909,13 @@ function _load_errors() { var _util; function _load_util() { - return _util = __webpack_require__(221); + return _util = __webpack_require__(219); } var _typos; function _load_typos() { - return _typos = _interopRequireDefault(__webpack_require__(587)); + return _typos = _interopRequireDefault(__webpack_require__(555)); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -39010,7 +39073,7 @@ function cleanDependencies(info, isRoot, reporter, warn) { // getting tag from 19.1.3.6 Object.prototype.toString() var cof = __webpack_require__(69); -var TAG = __webpack_require__(20)('toStringTag'); +var TAG = __webpack_require__(21)('toStringTag'); // ES3 wrong here var ARG = cof(function () { return arguments; }()) == 'Arguments'; @@ -39059,13 +39122,13 @@ module.exports = document && document.documentElement; var LIBRARY = __webpack_require__(93); var $export = __webpack_require__(60); -var redefine = __webpack_require__(251); +var redefine = __webpack_require__(248); var hide = __webpack_require__(42); -var Iterators = __webpack_require__(53); -var $iterCreate = __webpack_require__(242); +var Iterators = __webpack_require__(54); +var $iterCreate = __webpack_require__(239); var setToStringTag = __webpack_require__(95); -var getPrototypeOf = __webpack_require__(248); -var ITERATOR = __webpack_require__(20)('iterator'); +var getPrototypeOf = __webpack_require__(245); +var ITERATOR = __webpack_require__(21)('iterator'); var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next` var FF_ITERATOR = '@@iterator'; var KEYS = 'keys'; @@ -39145,7 +39208,7 @@ module.exports = function (exec) { /***/ (function(module, exports, __webpack_require__) { var anObject = __webpack_require__(35); -var isObject = __webpack_require__(52); +var isObject = __webpack_require__(53); var newPromiseCapability = __webpack_require__(94); module.exports = function (C, x) { @@ -39197,7 +39260,7 @@ var store = global[SHARED] || (global[SHARED] = {}); // 7.3.20 SpeciesConstructor(O, defaultConstructor) var anObject = __webpack_require__(35); var aFunction = __webpack_require__(68); -var SPECIES = __webpack_require__(20)('species'); +var SPECIES = __webpack_require__(21)('species'); module.exports = function (O, D) { var C = anObject(O).constructor; var S; @@ -39210,7 +39273,7 @@ module.exports = function (O, D) { /***/ (function(module, exports, __webpack_require__) { var ctx = __webpack_require__(70); -var invoke = __webpack_require__(239); +var invoke = __webpack_require__(236); var html = __webpack_require__(128); var cel = __webpack_require__(92); var global = __webpack_require__(17); @@ -39989,7 +40052,7 @@ ECFieldElementFp.prototype.modReduce = function(x) { u = u.multiply(this.getR()); } - x = u.add(v); + x = u.add(v); } while (x.compareTo(q) >= 0) { @@ -40127,13 +40190,13 @@ realpath.realpathSync = realpathSync realpath.monkeypatch = monkeypatch realpath.unmonkeypatch = unmonkeypatch -var fs = __webpack_require__(5) +var fs = __webpack_require__(4) var origRealpath = fs.realpath var origRealpathSync = fs.realpathSync var version = process.version var ok = /^v[0-5]\./.test(version) -var old = __webpack_require__(271) +var old = __webpack_require__(268) function newError (er) { return er && er.syscall === 'realpath' && ( @@ -40508,7 +40571,7 @@ module.exports = new Schema({ /***/ (function(module, exports, __webpack_require__) { var path = __webpack_require__(0); -var fs = __webpack_require__(5); +var fs = __webpack_require__(4); var _0777 = parseInt('0777', 8); module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; @@ -40521,18 +40584,18 @@ function mkdirP (p, opts, f, made) { else if (!opts || typeof opts !== 'object') { opts = { mode: opts }; } - + var mode = opts.mode; var xfs = opts.fs || fs; - + if (mode === undefined) { mode = _0777 & (~process.umask()); } if (!made) made = null; - + var cb = f || function () {}; p = path.resolve(p); - + xfs.mkdir(p, mode, function (er) { if (!er) { made = made || p; @@ -40565,10 +40628,10 @@ mkdirP.sync = function sync (p, opts, made) { if (!opts || typeof opts !== 'object') { opts = { mode: opts }; } - + var mode = opts.mode; var xfs = opts.fs || fs; - + if (mode === undefined) { mode = _0777 & (~process.umask()); } @@ -42760,7 +42823,7 @@ Object.defineProperty(exports, "__esModule", { var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -42780,7 +42843,7 @@ function _load_executeLifecycleScript() { var _path; function _load_path() { - return _path = __webpack_require__(377); + return _path = __webpack_require__(371); } var _conversion; @@ -42792,7 +42855,7 @@ function _load_conversion() { var _index; function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(220)); + return _index = _interopRequireDefault(__webpack_require__(218)); } var _errors; @@ -42804,7 +42867,7 @@ function _load_errors() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _constants; @@ -42816,25 +42879,25 @@ function _load_constants() { var _packageConstraintResolver; function _load_packageConstraintResolver() { - return _packageConstraintResolver = _interopRequireDefault(__webpack_require__(555)); + return _packageConstraintResolver = _interopRequireDefault(__webpack_require__(523)); } var _requestManager; function _load_requestManager() { - return _requestManager = _interopRequireDefault(__webpack_require__(378)); + return _requestManager = _interopRequireDefault(__webpack_require__(372)); } var _index2; function _load_index2() { - return _index2 = __webpack_require__(57); + return _index2 = __webpack_require__(58); } var _index3; function _load_index3() { - return _index3 = __webpack_require__(200); + return _index3 = __webpack_require__(201); } var _map; @@ -42848,10 +42911,10 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const crypto = __webpack_require__(11); -const detectIndent = __webpack_require__(635); +const detectIndent = __webpack_require__(603); const invariant = __webpack_require__(9); const path = __webpack_require__(0); -const micromatch = __webpack_require__(114); +const micromatch = __webpack_require__(115); const isCi = __webpack_require__(397); function sortObject(object) { @@ -43940,7 +44003,7 @@ function _load_asyncToGenerator() { var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } let run = exports.run = (() => { @@ -43992,7 +44055,7 @@ function _load_index() { var _list; function _load_list() { - return _list = __webpack_require__(358); + return _list = __webpack_require__(352); } var _install; @@ -44016,7 +44079,7 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _invariant; @@ -44610,13 +44673,13 @@ exports.hasWrapper = hasWrapper; var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _filter; function _load_filter() { - return _filter = __webpack_require__(372); + return _filter = __webpack_require__(366); } var _errors; @@ -44629,10 +44692,10 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -const zlib = __webpack_require__(198); +const zlib = __webpack_require__(199); const path = __webpack_require__(0); -const tar = __webpack_require__(193); -const fs2 = __webpack_require__(5); +const tar = __webpack_require__(194); +const fs2 = __webpack_require__(4); const depsFor = __webpack_require__(678); const FOLDERS_IGNORE = [ @@ -44642,7 +44705,7 @@ const FOLDERS_IGNORE = [ const DEFAULT_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([...FOLDERS_IGNORE, // ignore cruft -'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.npmignore', '.gitignore', '.DS_Store']); +'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.yarnrc.yml', '.npmignore', '.gitignore', '.DS_Store']); const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([ // never ignore these files @@ -44651,6 +44714,7 @@ const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([ function packWithIgnoreAndHeaders(cwd, ignoreFunction, { mapHeader } = {}) { return tar.pack(cwd, { ignore: ignoreFunction, + sort: true, map: header => { const suffix = header.name === '.' ? '' : `/${header.name}`; header.name = `package${suffix}`; @@ -44690,7 +44754,7 @@ function _load_asyncToGenerator() { var _index; function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(220)); + return _index = _interopRequireDefault(__webpack_require__(218)); } var _constants; @@ -44702,13 +44766,13 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _mutex; function _load_mutex() { - return _mutex = _interopRequireDefault(__webpack_require__(375)); + return _mutex = _interopRequireDefault(__webpack_require__(369)); } 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; } } @@ -44717,7 +44781,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de /* eslint no-unused-vars: 0 */ -const cmdShim = __webpack_require__(201); +const cmdShim = __webpack_require__(202); const path = __webpack_require__(0); class BaseFetcher { @@ -44954,6 +45018,139 @@ function guessName(source) { /* 170 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.satisfiesWithPrereleases = satisfiesWithPrereleases; +exports.diffWithUnstable = diffWithUnstable; + +var _semver; + +function _load_semver() { + return _semver = _interopRequireDefault(__webpack_require__(22)); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Returns whether the given semver version satisfies the given range. Notably this supports + * prerelease versions so that "2.0.0-rc.0" satisfies the range ">=1.0.0", for example. + */ + +function satisfiesWithPrereleases(version, range, loose = false) { + let semverRange; + try { + // $FlowFixMe: Add a definition for the Range class + semverRange = new (_semver || _load_semver()).default.Range(range, loose); + } catch (err) { + return false; + } + + if (!version) { + return false; + } + let semverVersion; + try { + semverVersion = new (_semver || _load_semver()).default.SemVer(version, semverRange.loose); + } catch (err) { + return false; + } + + // A range has multiple sets of comparators. A version must satisfy all comparators in a set + // and at least one set to satisfy the range. + return semverRange.set.some(comparatorSet => { + // node-semver converts ~ and ^ ranges into pairs of >= and < ranges but the upper bounds don't + // properly exclude prerelease versions. For example, "^1.0.0" is converted to ">=1.0.0 <2.0.0", + // which includes "2.0.0-pre" since prerelease versions are lower than their non-prerelease + // counterparts. As a practical workaround we make upper-bound ranges exclude prereleases and + // convert "<2.0.0" to "<2.0.0-0", for example. + comparatorSet = comparatorSet.map(comparator => { + if (comparator.operator !== '<' || !comparator.value || comparator.semver.prerelease.length) { + return comparator; + } + + // "0" is the lowest prerelease version + comparator.semver.inc('pre', 0); + + const comparatorString = comparator.operator + comparator.semver.version; + // $FlowFixMe: Add a definition for the Comparator class + return new (_semver || _load_semver()).default.Comparator(comparatorString, comparator.loose); + }); + + return !comparatorSet.some(comparator => !comparator.test(semverVersion)); + }); +} + +const PRE_RELEASES = { + major: 'premajor', + minor: 'preminor', + patch: 'prepatch' +}; + +/** + * Returns the difference between two versions as a semantic string representation. + * Similar to the `diff` method in node-semver, but it also accounts for unstable versions, + * like 0.x.x or 0.0.x. + */ + +function diffWithUnstable(version1, version2) { + if ((_semver || _load_semver()).default.eq(version1, version2) === false) { + const v1 = (_semver || _load_semver()).default.parse(version1); + const v2 = (_semver || _load_semver()).default.parse(version2); + + if (v1 != null && v2 != null) { + const isPreRelease = v1.prerelease.length > 0 || v2.prerelease.length > 0; + const preMajor = v1.major === 0 || v2.major === 0; + const preMinor = preMajor && (v1.minor === 0 || v2.minor === 0); + + let diff = null; + + if (v1.major !== v2.major) { + diff = 'major'; + } else if (v1.minor !== v2.minor) { + if (preMajor) { + // If the major version number is zero (0.x.x), treat a change + // of the minor version number as a major change. + diff = 'major'; + } else { + diff = 'minor'; + } + } else if (v1.patch !== v2.patch) { + if (preMinor) { + // If the major & minor version numbers are zero (0.0.x), treat a change + // of the patch version number as a major change. + diff = 'major'; + } else if (preMajor) { + // If the major version number is zero (0.x.x), treat a change + // of the patch version number as a minor change. + diff = 'minor'; + } else { + diff = 'patch'; + } + } + + if (isPreRelease) { + if (diff != null) { + diff = PRE_RELEASES[diff]; + } else { + diff = 'prerelease'; + } + } + + return diff; + } + } + + return null; +} + +/***/ }), +/* 171 */ +/***/ (function(module, exports, __webpack_require__) { + // fallback for non-array-like ES3 and non-enumerable old V8 strings var cof = __webpack_require__(69); // eslint-disable-next-line no-prototype-builtins @@ -44963,11 +45160,11 @@ module.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) { /***/ }), -/* 171 */ +/* 172 */ /***/ (function(module, exports, __webpack_require__) { // 19.1.2.14 / 15.2.3.14 Object.keys(O) -var $keys = __webpack_require__(249); +var $keys = __webpack_require__(246); var enumBugKeys = __webpack_require__(127); module.exports = Object.keys || function keys(O) { @@ -44976,7 +45173,7 @@ module.exports = Object.keys || function keys(O) { /***/ }), -/* 172 */ +/* 173 */ /***/ (function(module, exports, __webpack_require__) { // 7.1.13 ToObject(argument) @@ -44987,7 +45184,7 @@ module.exports = function (it) { /***/ }), -/* 173 */ +/* 174 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(83); @@ -45080,7 +45277,7 @@ module.exports = eos; /***/ }), -/* 174 */ +/* 175 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2012 Joyent, Inc. All rights reserved. @@ -45198,13 +45395,13 @@ module.exports = { /***/ }), -/* 175 */ +/* 176 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var chalk = __webpack_require__(30); -var figures = __webpack_require__(270); +var figures = __webpack_require__(267); /** * Separator object @@ -45242,7 +45439,7 @@ module.exports = Separator; /***/ }), -/* 176 */ +/* 177 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45302,7 +45499,7 @@ module.exports = Paginator; /***/ }), -/* 177 */ +/* 178 */ /***/ (function(module, exports) { /*! @@ -45319,7 +45516,7 @@ module.exports = function isExtglob(str) { /***/ }), -/* 178 */ +/* 179 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -45329,7 +45526,7 @@ module.exports = function isExtglob(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(177); +var isExtglob = __webpack_require__(178); module.exports = function isGlob(str) { return typeof str === 'string' @@ -45338,7 +45535,7 @@ module.exports = function isGlob(str) { }; /***/ }), -/* 179 */ +/* 180 */ /***/ (function(module, exports, __webpack_require__) { var isBuffer = __webpack_require__(729); @@ -45460,7 +45657,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 180 */ +/* 181 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45511,7 +45708,7 @@ function nextTick(fn, arg1, arg2, arg3) { /***/ }), -/* 181 */ +/* 182 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45579,7 +45776,7 @@ runAsync.cb = function (func, cb) { /***/ }), -/* 182 */ +/* 183 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45590,7 +45787,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ConnectableObservable", function() { return __WEBPACK_IMPORTED_MODULE_1__internal_observable_ConnectableObservable__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_operators_groupBy__ = __webpack_require__(433); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "GroupedObservable", function() { return __WEBPACK_IMPORTED_MODULE_2__internal_operators_groupBy__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__internal_symbol_observable__ = __webpack_require__(117); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__internal_symbol_observable__ = __webpack_require__(118); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "observable", function() { return __WEBPACK_IMPORTED_MODULE_3__internal_symbol_observable__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_Subject__ = __webpack_require__(36); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Subject", function() { return __WEBPACK_IMPORTED_MODULE_4__internal_Subject__["a"]; }); @@ -45598,7 +45795,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "BehaviorSubject", function() { return __WEBPACK_IMPORTED_MODULE_5__internal_BehaviorSubject__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_ReplaySubject__ = __webpack_require__(308); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ReplaySubject", function() { return __WEBPACK_IMPORTED_MODULE_6__internal_ReplaySubject__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__internal_AsyncSubject__ = __webpack_require__(183); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__internal_AsyncSubject__ = __webpack_require__(184); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "AsyncSubject", function() { return __WEBPACK_IMPORTED_MODULE_7__internal_AsyncSubject__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__internal_scheduler_asap__ = __webpack_require__(438); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "asapScheduler", function() { return __WEBPACK_IMPORTED_MODULE_8__internal_scheduler_asap__["a"]; }); @@ -45617,13 +45814,13 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Subscription", function() { return __WEBPACK_IMPORTED_MODULE_14__internal_Subscription__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__internal_Subscriber__ = __webpack_require__(7); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Subscriber", function() { return __WEBPACK_IMPORTED_MODULE_15__internal_Subscriber__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__internal_Notification__ = __webpack_require__(184); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__internal_Notification__ = __webpack_require__(185); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Notification", function() { return __WEBPACK_IMPORTED_MODULE_16__internal_Notification__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__internal_util_pipe__ = __webpack_require__(324); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "pipe", function() { return __WEBPACK_IMPORTED_MODULE_17__internal_util_pipe__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__internal_util_noop__ = __webpack_require__(191); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__internal_util_noop__ = __webpack_require__(192); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "noop", function() { return __WEBPACK_IMPORTED_MODULE_18__internal_util_noop__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__internal_util_identity__ = __webpack_require__(118); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__internal_util_identity__ = __webpack_require__(119); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return __WEBPACK_IMPORTED_MODULE_19__internal_util_identity__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_20__internal_util_isObservable__ = __webpack_require__(930); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "isObservable", function() { return __WEBPACK_IMPORTED_MODULE_20__internal_util_isObservable__["a"]; }); @@ -45631,7 +45828,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ArgumentOutOfRangeError", function() { return __WEBPACK_IMPORTED_MODULE_21__internal_util_ArgumentOutOfRangeError__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__internal_util_EmptyError__ = __webpack_require__(153); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "EmptyError", function() { return __WEBPACK_IMPORTED_MODULE_22__internal_util_EmptyError__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__internal_util_ObjectUnsubscribedError__ = __webpack_require__(189); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__internal_util_ObjectUnsubscribedError__ = __webpack_require__(190); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectUnsubscribedError", function() { return __WEBPACK_IMPORTED_MODULE_23__internal_util_ObjectUnsubscribedError__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_24__internal_util_UnsubscriptionError__ = __webpack_require__(441); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "UnsubscriptionError", function() { return __WEBPACK_IMPORTED_MODULE_24__internal_util_UnsubscriptionError__["a"]; }); @@ -45643,7 +45840,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "bindNodeCallback", function() { return __WEBPACK_IMPORTED_MODULE_27__internal_observable_bindNodeCallback__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_28__internal_observable_combineLatest__ = __webpack_require__(309); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return __WEBPACK_IMPORTED_MODULE_28__internal_observable_combineLatest__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_29__internal_observable_concat__ = __webpack_require__(186); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_29__internal_observable_concat__ = __webpack_require__(187); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return __WEBPACK_IMPORTED_MODULE_29__internal_observable_concat__["a"]; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_30__internal_observable_defer__ = __webpack_require__(310); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "defer", function() { return __WEBPACK_IMPORTED_MODULE_30__internal_observable_defer__["a"]; }); @@ -45687,7 +45884,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return __WEBPACK_IMPORTED_MODULE_49__internal_observable_zip__["a"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "EMPTY", function() { return __WEBPACK_IMPORTED_MODULE_31__internal_observable_empty__["b"]; }); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "NEVER", function() { return __WEBPACK_IMPORTED_MODULE_40__internal_observable_never__["b"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_50__internal_config__ = __webpack_require__(185); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_50__internal_config__ = __webpack_require__(186); /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "config", function() { return __WEBPACK_IMPORTED_MODULE_50__internal_config__["a"]; }); /** PURE_IMPORTS_START PURE_IMPORTS_END */ @@ -45747,7 +45944,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /***/ }), -/* 183 */ +/* 184 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45805,7 +46002,7 @@ var AsyncSubject = /*@__PURE__*/ (function (_super) { /***/ }), -/* 184 */ +/* 185 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45886,7 +46083,7 @@ var Notification = /*@__PURE__*/ (function () { /***/ }), -/* 185 */ +/* 186 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45913,7 +46110,7 @@ var config = { /***/ }), -/* 186 */ +/* 187 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45941,7 +46138,7 @@ function concat() { /***/ }), -/* 187 */ +/* 188 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -45969,7 +46166,7 @@ function reduce(accumulator, seed) { /***/ }), -/* 188 */ +/* 189 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -46000,7 +46197,7 @@ function defaultErrorFactory() { /***/ }), -/* 189 */ +/* 190 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -46018,7 +46215,7 @@ var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl; /***/ }), -/* 190 */ +/* 191 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -46033,7 +46230,7 @@ function isNumeric(val) { /***/ }), -/* 191 */ +/* 192 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -46044,7 +46241,7 @@ function noop() { } /***/ }), -/* 192 */ +/* 193 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2015 Joyent, Inc. @@ -46116,7 +46313,7 @@ function readSSHPrivate(type, buf, options) { var rounds = kdfOptsBuf.readInt(); var cinf = utils.opensshCipherInfo(cipher); if (bcrypt === undefined) { - bcrypt = __webpack_require__(379); + bcrypt = __webpack_require__(373); } if (typeof (options.passphrase) === 'string') { @@ -46237,7 +46434,7 @@ function write(key, options) { kdfopts = kdfssh.toBuffer(); if (bcrypt === undefined) { - bcrypt = __webpack_require__(379); + bcrypt = __webpack_require__(373); } var pass = new Uint8Array(passphrase); var salti = new Uint8Array(salt); @@ -46312,14 +46509,14 @@ function write(key, options) { /***/ }), -/* 193 */ +/* 194 */ /***/ (function(module, exports, __webpack_require__) { -var chownr = __webpack_require__(600) +var chownr = __webpack_require__(568) var tar = __webpack_require__(460) var pump = __webpack_require__(781) var mkdirp = __webpack_require__(145) -var fs = __webpack_require__(5) +var fs = __webpack_require__(4) var path = __webpack_require__(0) var os = __webpack_require__(46) @@ -46663,37 +46860,37 @@ function mkdirfix (name, opts, cb) { /***/ }), -/* 194 */ +/* 195 */ /***/ (function(module, exports) { -module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.21.1","license":"BSD-2-Clause","preferGlobal":true,"description":"đŸ“Ļ🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}} +module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.22.19","packageManager":"yarn@1.22.17","license":"BSD-2-Clause","preferGlobal":true,"description":"đŸ“Ļ🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}} /***/ }), -/* 195 */ +/* 196 */ /***/ (function(module, exports) { module.exports = require("https"); /***/ }), -/* 196 */ +/* 197 */ /***/ (function(module, exports) { module.exports = require("querystring"); /***/ }), -/* 197 */ +/* 198 */ /***/ (function(module, exports) { module.exports = require("readline"); /***/ }), -/* 198 */ +/* 199 */ /***/ (function(module, exports) { module.exports = require("zlib"); /***/ }), -/* 199 */ +/* 200 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46719,7 +46916,7 @@ function _load_constants() { var _package; function _load_package() { - return _package = __webpack_require__(194); + return _package = __webpack_require__(195); } const NODE_VERSION = process.version; @@ -46827,7 +47024,7 @@ function stringify(obj, noHeader, enableVersions) { } /***/ }), -/* 200 */ +/* 201 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46840,7 +47037,7 @@ Object.defineProperty(exports, "__esModule", { var _consoleReporter; function _load_consoleReporter() { - return _consoleReporter = __webpack_require__(561); + return _consoleReporter = __webpack_require__(529); } Object.defineProperty(exports, 'ConsoleReporter', { @@ -46853,7 +47050,7 @@ Object.defineProperty(exports, 'ConsoleReporter', { var _bufferReporter; function _load_bufferReporter() { - return _bufferReporter = __webpack_require__(560); + return _bufferReporter = __webpack_require__(528); } Object.defineProperty(exports, 'BufferReporter', { @@ -46866,7 +47063,7 @@ Object.defineProperty(exports, 'BufferReporter', { var _eventReporter; function _load_eventReporter() { - return _eventReporter = __webpack_require__(565); + return _eventReporter = __webpack_require__(533); } Object.defineProperty(exports, 'EventReporter', { @@ -46879,7 +47076,7 @@ Object.defineProperty(exports, 'EventReporter', { var _jsonReporter; function _load_jsonReporter() { - return _jsonReporter = __webpack_require__(213); + return _jsonReporter = __webpack_require__(211); } Object.defineProperty(exports, 'JSONReporter', { @@ -46892,7 +47089,7 @@ Object.defineProperty(exports, 'JSONReporter', { var _noopReporter; function _load_noopReporter() { - return _noopReporter = __webpack_require__(569); + return _noopReporter = __webpack_require__(537); } Object.defineProperty(exports, 'NoopReporter', { @@ -46918,7 +47115,7 @@ Object.defineProperty(exports, 'Reporter', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /***/ }), -/* 201 */ +/* 202 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47190,389 +47387,8 @@ function normalizePathEnvVar (nodePath) { } -/***/ }), -/* 202 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var resolve = __webpack_require__(203); - -module.exports = { - Validation: errorSubclass(ValidationError), - MissingRef: errorSubclass(MissingRefError) -}; - - -function ValidationError(errors) { - this.message = 'validation failed'; - this.errors = errors; - this.ajv = this.validation = true; -} - - -MissingRefError.message = function (baseId, ref) { - return 'can\'t resolve reference ' + ref + ' from id ' + baseId; -}; - - -function MissingRefError(baseId, ref, message) { - this.message = message || MissingRefError.message(baseId, ref); - this.missingRef = resolve.url(https://github.com/baseId,%20ref); - this.missingSchema = resolve.normalizeId(resolve.fullPath(this.missingRef)); -} - - -function errorSubclass(Subclass) { - Subclass.prototype = Object.create(Error.prototype); - Subclass.prototype.constructor = Subclass; - return Subclass; -} - - /***/ }), /* 203 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var url = __webpack_require__(24) - , equal = __webpack_require__(204) - , util = __webpack_require__(106) - , SchemaObject = __webpack_require__(339) - , traverse = __webpack_require__(503); - -module.exports = resolve; - -resolve.normalizeId = normalizeId; -resolve.fullPath = getFullPath; -resolve.url = resolveUrl; -resolve.ids = resolveIds; -resolve.inlineRef = inlineRef; -resolve.schema = resolveSchema; - -/** - * [resolve and compile the references ($ref)] - * @this Ajv - * @param {Function} compile reference to schema compilation funciton (localCompile) - * @param {Object} root object with information about the root schema for the current schema - * @param {String} ref reference to resolve - * @return {Object|Function} schema object (if the schema can be inlined) or validation function - */ -function resolve(compile, root, ref) { - /* jshint validthis: true */ - var refVal = this._refs[ref]; - if (typeof refVal == 'string') { - if (this._refs[refVal]) refVal = this._refs[refVal]; - else return resolve.call(this, compile, root, refVal); - } - - refVal = refVal || this._schemas[ref]; - if (refVal instanceof SchemaObject) { - return inlineRef(refVal.schema, this._opts.inlineRefs) - ? refVal.schema - : refVal.validate || this._compile(refVal); - } - - var res = resolveSchema.call(this, root, ref); - var schema, v, baseId; - if (res) { - schema = res.schema; - root = res.root; - baseId = res.baseId; - } - - if (schema instanceof SchemaObject) { - v = schema.validate || compile.call(this, schema.schema, root, undefined, baseId); - } else if (schema !== undefined) { - v = inlineRef(schema, this._opts.inlineRefs) - ? schema - : compile.call(this, schema, root, undefined, baseId); - } - - return v; -} - - -/** - * Resolve schema, its root and baseId - * @this Ajv - * @param {Object} root root object with properties schema, refVal, refs - * @param {String} ref reference to resolve - * @return {Object} object with properties schema, root, baseId - */ -function resolveSchema(root, ref) { - /* jshint validthis: true */ - var p = url.parse(ref, false, true) - , refPath = _getFullPath(p) - , baseId = getFullPath(this._getId(root.schema)); - if (refPath !== baseId) { - var id = normalizeId(refPath); - var refVal = this._refs[id]; - if (typeof refVal == 'string') { - return resolveRecursive.call(this, root, refVal, p); - } else if (refVal instanceof SchemaObject) { - if (!refVal.validate) this._compile(refVal); - root = refVal; - } else { - refVal = this._schemas[id]; - if (refVal instanceof SchemaObject) { - if (!refVal.validate) this._compile(refVal); - if (id == normalizeId(ref)) - return { schema: refVal, root: root, baseId: baseId }; - root = refVal; - } else { - return; - } - } - if (!root.schema) return; - baseId = getFullPath(this._getId(root.schema)); - } - return getJsonPointer.call(this, p, baseId, root.schema, root); -} - - -/* @this Ajv */ -function resolveRecursive(root, ref, parsedRef) { - /* jshint validthis: true */ - var res = resolveSchema.call(this, root, ref); - if (res) { - var schema = res.schema; - var baseId = res.baseId; - root = res.root; - var id = this._getId(schema); - if (id) baseId = resolveUrl(baseId, id); - return getJsonPointer.call(this, parsedRef, baseId, schema, root); - } -} - - -var PREVENT_SCOPE_CHANGE = util.toHash(['properties', 'patternProperties', 'enum', 'dependencies', 'definitions']); -/* @this Ajv */ -function getJsonPointer(parsedRef, baseId, schema, root) { - /* jshint validthis: true */ - parsedRef.hash = parsedRef.hash || ''; - if (parsedRef.hash.slice(0,2) != '#/') return; - var parts = parsedRef.hash.split('/'); - - for (var i = 1; i < parts.length; i++) { - var part = parts[i]; - if (part) { - part = util.unescapeFragment(part); - schema = schema[part]; - if (schema === undefined) break; - var id; - if (!PREVENT_SCOPE_CHANGE[part]) { - id = this._getId(schema); - if (id) baseId = resolveUrl(baseId, id); - if (schema.$ref) { - var $ref = resolveUrl(baseId, schema.$ref); - var res = resolveSchema.call(this, root, $ref); - if (res) { - schema = res.schema; - root = res.root; - baseId = res.baseId; - } - } - } - } - } - if (schema !== undefined && schema !== root.schema) - return { schema: schema, root: root, baseId: baseId }; -} - - -var SIMPLE_INLINED = util.toHash([ - 'type', 'format', 'pattern', - 'maxLength', 'minLength', - 'maxProperties', 'minProperties', - 'maxItems', 'minItems', - 'maximum', 'minimum', - 'uniqueItems', 'multipleOf', - 'required', 'enum' -]); -function inlineRef(schema, limit) { - if (limit === false) return false; - if (limit === undefined || limit === true) return checkNoRef(schema); - else if (limit) return countKeys(schema) <= limit; -} - - -function checkNoRef(schema) { - var item; - if (Array.isArray(schema)) { - for (var i=0; i All rights reserved. @@ -47591,7 +47407,7 @@ module.exports = { /***/ }), -/* 206 */ +/* 204 */ /***/ (function(module, exports) { // Copyright 2011 Mark Cavage All rights reserved. @@ -47633,7 +47449,7 @@ module.exports = { /***/ }), -/* 207 */ +/* 205 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47913,7 +47729,7 @@ function hasWrapper(commander, args) { const requireLockfile = exports.requireLockfile = true; /***/ }), -/* 208 */ +/* 206 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47927,7 +47743,7 @@ exports.integrityErrors = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -47945,7 +47761,7 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _misc; @@ -47957,7 +47773,7 @@ function _load_misc() { var _packageNameUtils; function _load_packageNameUtils() { - return _packageNameUtils = __webpack_require__(222); + return _packageNameUtils = __webpack_require__(220); } var _workspaceLayout; @@ -48535,7 +48351,7 @@ class InstallationIntegrityChecker { exports.default = InstallationIntegrityChecker; /***/ }), -/* 209 */ +/* 207 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48570,13 +48386,13 @@ function _load_misc() { var _yarnVersion; function _load_yarnVersion() { - return _yarnVersion = __webpack_require__(120); + return _yarnVersion = __webpack_require__(105); } var _semver; function _load_semver() { - return _semver = __webpack_require__(224); + return _semver = __webpack_require__(170); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -48707,9 +48523,7 @@ function checkOne(info, config, ignoreEngines) { ref.ignore = true; ref.incompatible = true; - reporter.info(`${human}: ${msg}`); if (!didIgnore) { - reporter.info(reporter.lang('optionalCompatibilityExcluded', human)); didIgnore = true; } } else { @@ -48804,7 +48618,7 @@ function shouldCheck(manifest, options) { } /***/ }), -/* 210 */ +/* 208 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48931,19 +48745,19 @@ function _load_errors() { var _index; function _load_index() { - return _index = _interopRequireWildcard(__webpack_require__(552)); + return _index = _interopRequireWildcard(__webpack_require__(520)); } var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _promise; function _load_promise() { - return _promise = _interopRequireWildcard(__webpack_require__(50)); + return _promise = _interopRequireWildcard(__webpack_require__(51)); } 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; } } @@ -49030,7 +48844,7 @@ function fetch(pkgs, config) { } /***/ }), -/* 211 */ +/* 209 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49071,7 +48885,7 @@ let linkBin = exports.linkBin = (() => { var _packageHoister; function _load_packageHoister() { - return _packageHoister = _interopRequireDefault(__webpack_require__(556)); + return _packageHoister = _interopRequireDefault(__webpack_require__(524)); } var _constants; @@ -49083,7 +48897,7 @@ function _load_constants() { var _promise; function _load_promise() { - return _promise = _interopRequireWildcard(__webpack_require__(50)); + return _promise = _interopRequireWildcard(__webpack_require__(51)); } var _normalizePattern2; @@ -49101,19 +48915,19 @@ function _load_misc() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _mutex; function _load_mutex() { - return _mutex = _interopRequireDefault(__webpack_require__(375)); + return _mutex = _interopRequireDefault(__webpack_require__(369)); } var _semver; function _load_semver() { - return _semver = __webpack_require__(224); + return _semver = __webpack_require__(170); } var _workspaceLayout; @@ -49128,7 +48942,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const invariant = __webpack_require__(9); -const cmdShim = __webpack_require__(201); +const cmdShim = __webpack_require__(202); const path = __webpack_require__(0); const semver = __webpack_require__(22); // Concurrency for creating bin links disabled because of the issue #1961 @@ -50170,7 +49984,7 @@ class PackageLinker { exports.default = PackageLinker; /***/ }), -/* 212 */ +/* 210 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50192,7 +50006,7 @@ function _load_tty() { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -const readline = __webpack_require__(197); +const readline = __webpack_require__(198); var _require = __webpack_require__(30); @@ -50261,7 +50075,7 @@ function clearNthLine(stdout, n) { } /***/ }), -/* 213 */ +/* 211 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50274,7 +50088,7 @@ Object.defineProperty(exports, "__esModule", { var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _baseReporter; @@ -50455,7 +50269,7 @@ class JSONReporter extends (_baseReporter || _load_baseReporter()).default { exports.default = JSONReporter; /***/ }), -/* 214 */ +/* 212 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50493,13 +50307,13 @@ function _load_normalizePattern() { var _parsePackagePath; function _load_parsePackagePath() { - return _parsePackagePath = _interopRequireDefault(__webpack_require__(376)); + return _parsePackagePath = _interopRequireDefault(__webpack_require__(370)); } var _parsePackagePath2; function _load_parsePackagePath2() { - return _parsePackagePath2 = __webpack_require__(376); + return _parsePackagePath2 = __webpack_require__(370); } var _resolvers; @@ -50603,7 +50417,7 @@ const shouldUpdateLockfile = exports.shouldUpdateLockfile = (lockfileEntry, reso }; /***/ }), -/* 215 */ +/* 213 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50635,7 +50449,7 @@ function _load_invariant() { var _uuid; function _load_uuid() { - return _uuid = _interopRequireDefault(__webpack_require__(119)); + return _uuid = _interopRequireDefault(__webpack_require__(120)); } var _errors; @@ -50659,7 +50473,7 @@ function _load_misc() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -50741,7 +50555,7 @@ FileResolver.protocol = 'file'; FileResolver.prefixMatcher = /^\.{1,2}\//; /***/ }), -/* 216 */ +/* 214 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50817,7 +50631,7 @@ exports.default = GistResolver; GistResolver.protocol = 'gist'; /***/ }), -/* 217 */ +/* 215 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50836,7 +50650,7 @@ function _load_asyncToGenerator() { var _cache; function _load_cache() { - return _cache = __webpack_require__(355); + return _cache = __webpack_require__(349); } var _errors; @@ -50848,7 +50662,7 @@ function _load_errors() { var _registryResolver; function _load_registryResolver() { - return _registryResolver = _interopRequireDefault(__webpack_require__(575)); + return _registryResolver = _interopRequireDefault(__webpack_require__(543)); } var _npmRegistry; @@ -50866,7 +50680,7 @@ function _load_map() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _constants; @@ -50878,7 +50692,7 @@ function _load_constants() { var _packageNameUtils; function _load_packageNameUtils() { - return _packageNameUtils = __webpack_require__(222); + return _packageNameUtils = __webpack_require__(220); } 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; } } @@ -51039,17 +50853,17 @@ class NpmResolver extends (_registryResolver || _load_registryResolver()).defaul // lockfile const shrunk = _this3.request.getLocked('tarball'); if (shrunk) { - if (_this3.config.packBuiltPackages && shrunk.prebuilt2Variants && shrunk._remote) { - const prebuilt2Variants = shrunk.prebuilt2Variants; - const prebuilt2Name = (0, (_packageNameUtils || _load_packageNameUtils()).getPlatformSpecificPackageFilename)(shrunk); + if (_this3.config.packBuiltPackages && shrunk.prebuiltVariants && shrunk._remote) { + const prebuiltVariants = shrunk.prebuiltVariants; + const prebuiltName = (0, (_packageNameUtils || _load_packageNameUtils()).getPlatformSpecificPackageFilename)(shrunk); const offlineMirrorPath = _this3.config.getOfflineMirrorPath(); - if (prebuilt2Variants[prebuilt2Name] && offlineMirrorPath) { - const filename = path.join(offlineMirrorPath, 'prebuilt2', prebuilt2Name + '.tgz'); + if (prebuiltVariants[prebuiltName] && offlineMirrorPath) { + const filename = path.join(offlineMirrorPath, 'prebuilt', prebuiltName + '.tgz'); const _remote = shrunk._remote; if (_remote && (yield (_fs || _load_fs()).exists(filename))) { _remote.reference = `file:${filename}`; - _remote.hash = prebuilt2Variants[prebuilt2Name]; + _remote.hash = prebuiltVariants[prebuiltName]; _remote.integrity = ssri.fromHex(_remote.hash, 'sha1').toString(); } } @@ -51106,7 +50920,7 @@ exports.default = NpmResolver; NpmResolver.registry = NPM_REGISTRY_ID; /***/ }), -/* 218 */ +/* 216 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -51186,19 +51000,19 @@ let fixTimes = (() => { var _fs; function _load_fs() { - return _fs = _interopRequireDefault(__webpack_require__(5)); + return _fs = _interopRequireDefault(__webpack_require__(4)); } var _promise; function _load_promise() { - return _promise = __webpack_require__(50); + return _promise = __webpack_require__(51); } var _fs2; function _load_fs2() { - return _fs2 = __webpack_require__(4); + return _fs2 = __webpack_require__(5); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -51304,7 +51118,7 @@ const copyWithBuffer = (() => { }; /***/ }), -/* 219 */ +/* 217 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -51323,7 +51137,7 @@ function _load_asyncToGenerator() { var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _invariant; @@ -51341,7 +51155,7 @@ function _load_string_decoder() { var _tarFs; function _load_tarFs() { - return _tarFs = _interopRequireDefault(__webpack_require__(193)); + return _tarFs = _interopRequireDefault(__webpack_require__(194)); } var _tarStream; @@ -51359,7 +51173,7 @@ function _load_url() { var _fs; function _load_fs() { - return _fs = __webpack_require__(5); + return _fs = __webpack_require__(4); } var _errors; @@ -51371,13 +51185,13 @@ function _load_errors() { var _gitSpawn; function _load_gitSpawn() { - return _gitSpawn = __webpack_require__(373); + return _gitSpawn = __webpack_require__(367); } var _gitRefResolver; function _load_gitRefResolver() { - return _gitRefResolver = __webpack_require__(581); + return _gitRefResolver = __webpack_require__(549); } var _crypto; @@ -51389,7 +51203,7 @@ function _load_crypto() { var _fs2; function _load_fs2() { - return _fs2 = _interopRequireWildcard(__webpack_require__(4)); + return _fs2 = _interopRequireWildcard(__webpack_require__(5)); } var _map; @@ -51948,7 +51762,7 @@ class Git { exports.default = Git; /***/ }), -/* 220 */ +/* 218 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -51967,7 +51781,7 @@ function _load_asyncToGenerator() { var _resolveRelative; function _load_resolveRelative() { - return _resolveRelative = _interopRequireDefault(__webpack_require__(586)); + return _resolveRelative = _interopRequireDefault(__webpack_require__(554)); } var _validate; @@ -51979,7 +51793,7 @@ function _load_validate() { var _fix; function _load_fix() { - return _fix = _interopRequireDefault(__webpack_require__(583)); + return _fix = _interopRequireDefault(__webpack_require__(551)); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -52035,7 +51849,7 @@ exports.default = (() => { })(); /***/ }), -/* 221 */ +/* 219 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52164,7 +51978,7 @@ function extractRepositoryUrl(repository) { } /***/ }), -/* 222 */ +/* 220 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52188,7 +52002,7 @@ function getSystemParams() { } /***/ }), -/* 223 */ +/* 221 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52216,140 +52030,7 @@ function isRootUser(uid) { } /***/ }), -/* 224 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.satisfiesWithPrereleases = satisfiesWithPrereleases; -exports.diffWithUnstable = diffWithUnstable; - -var _semver; - -function _load_semver() { - return _semver = _interopRequireDefault(__webpack_require__(22)); -} - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Returns whether the given semver version satisfies the given range. Notably this supports - * prerelease versions so that "2.0.0-rc.0" satisfies the range ">=1.0.0", for example. - */ - -function satisfiesWithPrereleases(version, range, loose = false) { - let semverRange; - try { - // $FlowFixMe: Add a definition for the Range class - semverRange = new (_semver || _load_semver()).default.Range(range, loose); - } catch (err) { - return false; - } - - if (!version) { - return false; - } - let semverVersion; - try { - semverVersion = new (_semver || _load_semver()).default.SemVer(version, semverRange.loose); - } catch (err) { - return false; - } - - // A range has multiple sets of comparators. A version must satisfy all comparators in a set - // and at least one set to satisfy the range. - return semverRange.set.some(comparatorSet => { - // node-semver converts ~ and ^ ranges into pairs of >= and < ranges but the upper bounds don't - // properly exclude prerelease versions. For example, "^1.0.0" is converted to ">=1.0.0 <2.0.0", - // which includes "2.0.0-pre" since prerelease versions are lower than their non-prerelease - // counterparts. As a practical workaround we make upper-bound ranges exclude prereleases and - // convert "<2.0.0" to "<2.0.0-0", for example. - comparatorSet = comparatorSet.map(comparator => { - if (comparator.operator !== '<' || !comparator.value || comparator.semver.prerelease.length) { - return comparator; - } - - // "0" is the lowest prerelease version - comparator.semver.inc('pre', 0); - - const comparatorString = comparator.operator + comparator.semver.version; - // $FlowFixMe: Add a definition for the Comparator class - return new (_semver || _load_semver()).default.Comparator(comparatorString, comparator.loose); - }); - - return !comparatorSet.some(comparator => !comparator.test(semverVersion)); - }); -} - -const PRE_RELEASES = { - major: 'premajor', - minor: 'preminor', - patch: 'prepatch' -}; - -/** - * Returns the difference between two versions as a semantic string representation. - * Similar to the `diff` method in node-semver, but it also accounts for unstable versions, - * like 0.x.x or 0.0.x. - */ - -function diffWithUnstable(version1, version2) { - if ((_semver || _load_semver()).default.eq(version1, version2) === false) { - const v1 = (_semver || _load_semver()).default.parse(version1); - const v2 = (_semver || _load_semver()).default.parse(version2); - - if (v1 != null && v2 != null) { - const isPreRelease = v1.prerelease.length > 0 || v2.prerelease.length > 0; - const preMajor = v1.major === 0 || v2.major === 0; - const preMinor = preMajor && (v1.minor === 0 || v2.minor === 0); - - let diff = null; - - if (v1.major !== v2.major) { - diff = 'major'; - } else if (v1.minor !== v2.minor) { - if (preMajor) { - // If the major version number is zero (0.x.x), treat a change - // of the minor version number as a major change. - diff = 'major'; - } else { - diff = 'minor'; - } - } else if (v1.patch !== v2.patch) { - if (preMinor) { - // If the major & minor version numbers are zero (0.0.x), treat a change - // of the patch version number as a major change. - diff = 'major'; - } else if (preMajor) { - // If the major version number is zero (0.x.x), treat a change - // of the patch version number as a minor change. - diff = 'minor'; - } else { - diff = 'patch'; - } - } - - if (isPreRelease) { - if (diff != null) { - diff = PRE_RELEASES[diff]; - } else { - diff = 'prerelease'; - } - } - - return diff; - } - } - - return null; -} - -/***/ }), -/* 225 */ +/* 222 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52415,7 +52096,7 @@ function getLocalAppDataDir() { } /***/ }), -/* 226 */ +/* 223 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52435,13 +52116,13 @@ function explodeHashedUrl(url) { } /***/ }), -/* 227 */ +/* 224 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = { "default": __webpack_require__(233), __esModule: true }; +module.exports = { "default": __webpack_require__(230), __esModule: true }; /***/ }), -/* 228 */ +/* 225 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52507,11 +52188,11 @@ function range(a, b, str) { /***/ }), -/* 229 */ +/* 226 */ /***/ (function(module, exports, __webpack_require__) { -var concatMap = __webpack_require__(232); -var balanced = __webpack_require__(228); +var concatMap = __webpack_require__(229); +var balanced = __webpack_require__(225); module.exports = expandTop; @@ -52714,7 +52395,7 @@ function expand(str, isTop) { /***/ }), -/* 230 */ +/* 227 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52785,7 +52466,7 @@ module.exports = function (str) { /***/ }), -/* 231 */ +/* 228 */ /***/ (function(module, exports) { function Caseless (dict) { @@ -52858,7 +52539,7 @@ module.exports.httpify = function (resp, headers) { /***/ }), -/* 232 */ +/* 229 */ /***/ (function(module, exports) { module.exports = function (xs, fn) { @@ -52877,27 +52558,27 @@ var isArray = Array.isArray || function (xs) { /***/ }), -/* 233 */ +/* 230 */ /***/ (function(module, exports, __webpack_require__) { -__webpack_require__(259); +__webpack_require__(256); +__webpack_require__(258); __webpack_require__(261); -__webpack_require__(264); +__webpack_require__(257); +__webpack_require__(259); __webpack_require__(260); -__webpack_require__(262); -__webpack_require__(263); module.exports = __webpack_require__(31).Promise; /***/ }), -/* 234 */ +/* 231 */ /***/ (function(module, exports) { module.exports = function () { /* empty */ }; /***/ }), -/* 235 */ +/* 232 */ /***/ (function(module, exports) { module.exports = function (it, Constructor, name, forbiddenField) { @@ -52908,14 +52589,14 @@ module.exports = function (it, Constructor, name, forbiddenField) { /***/ }), -/* 236 */ +/* 233 */ /***/ (function(module, exports, __webpack_require__) { // false -> Array#indexOf // true -> Array#includes var toIObject = __webpack_require__(98); var toLength = __webpack_require__(136); -var toAbsoluteIndex = __webpack_require__(254); +var toAbsoluteIndex = __webpack_require__(251); module.exports = function (IS_INCLUDES) { return function ($this, el, fromIndex) { var O = toIObject($this); @@ -52937,15 +52618,15 @@ module.exports = function (IS_INCLUDES) { /***/ }), -/* 237 */ +/* 234 */ /***/ (function(module, exports, __webpack_require__) { var ctx = __webpack_require__(70); -var call = __webpack_require__(241); -var isArrayIter = __webpack_require__(240); +var call = __webpack_require__(238); +var isArrayIter = __webpack_require__(237); var anObject = __webpack_require__(35); var toLength = __webpack_require__(136); -var getIterFn = __webpack_require__(257); +var getIterFn = __webpack_require__(254); var BREAK = {}; var RETURN = {}; var exports = module.exports = function (iterable, entries, fn, that, ITERATOR) { @@ -52968,16 +52649,16 @@ exports.RETURN = RETURN; /***/ }), -/* 238 */ +/* 235 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = !__webpack_require__(51) && !__webpack_require__(112)(function () { +module.exports = !__webpack_require__(52) && !__webpack_require__(112)(function () { return Object.defineProperty(__webpack_require__(92)('div'), 'a', { get: function () { return 7; } }).a != 7; }); /***/ }), -/* 239 */ +/* 236 */ /***/ (function(module, exports) { // fast apply, http://jsperf.lnkit.com/fast-apply/5 @@ -52999,12 +52680,12 @@ module.exports = function (fn, args, that) { /***/ }), -/* 240 */ +/* 237 */ /***/ (function(module, exports, __webpack_require__) { // check on default Array iterator -var Iterators = __webpack_require__(53); -var ITERATOR = __webpack_require__(20)('iterator'); +var Iterators = __webpack_require__(54); +var ITERATOR = __webpack_require__(21)('iterator'); var ArrayProto = Array.prototype; module.exports = function (it) { @@ -53013,7 +52694,7 @@ module.exports = function (it) { /***/ }), -/* 241 */ +/* 238 */ /***/ (function(module, exports, __webpack_require__) { // call something on iterator step with safe closing on error @@ -53031,18 +52712,18 @@ module.exports = function (iterator, fn, value, entries) { /***/ }), -/* 242 */ +/* 239 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var create = __webpack_require__(246); +var create = __webpack_require__(243); var descriptor = __webpack_require__(132); var setToStringTag = __webpack_require__(95); var IteratorPrototype = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]() -__webpack_require__(42)(IteratorPrototype, __webpack_require__(20)('iterator'), function () { return this; }); +__webpack_require__(42)(IteratorPrototype, __webpack_require__(21)('iterator'), function () { return this; }); module.exports = function (Constructor, NAME, next) { Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) }); @@ -53051,10 +52732,10 @@ module.exports = function (Constructor, NAME, next) { /***/ }), -/* 243 */ +/* 240 */ /***/ (function(module, exports, __webpack_require__) { -var ITERATOR = __webpack_require__(20)('iterator'); +var ITERATOR = __webpack_require__(21)('iterator'); var SAFE_CLOSING = false; try { @@ -53079,7 +52760,7 @@ module.exports = function (exec, skipClosing) { /***/ }), -/* 244 */ +/* 241 */ /***/ (function(module, exports) { module.exports = function (done, value) { @@ -53088,7 +52769,7 @@ module.exports = function (done, value) { /***/ }), -/* 245 */ +/* 242 */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(17); @@ -53163,12 +52844,12 @@ module.exports = function () { /***/ }), -/* 246 */ +/* 243 */ /***/ (function(module, exports, __webpack_require__) { // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) var anObject = __webpack_require__(35); -var dPs = __webpack_require__(247); +var dPs = __webpack_require__(244); var enumBugKeys = __webpack_require__(127); var IE_PROTO = __webpack_require__(96)('IE_PROTO'); var Empty = function () { /* empty */ }; @@ -53210,14 +52891,14 @@ module.exports = Object.create || function create(O, Properties) { /***/ }), -/* 247 */ +/* 244 */ /***/ (function(module, exports, __webpack_require__) { var dP = __webpack_require__(72); var anObject = __webpack_require__(35); -var getKeys = __webpack_require__(171); +var getKeys = __webpack_require__(172); -module.exports = __webpack_require__(51) ? Object.defineProperties : function defineProperties(O, Properties) { +module.exports = __webpack_require__(52) ? Object.defineProperties : function defineProperties(O, Properties) { anObject(O); var keys = getKeys(Properties); var length = keys.length; @@ -53229,12 +52910,12 @@ module.exports = __webpack_require__(51) ? Object.defineProperties : function de /***/ }), -/* 248 */ +/* 245 */ /***/ (function(module, exports, __webpack_require__) { // 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) var has = __webpack_require__(71); -var toObject = __webpack_require__(172); +var toObject = __webpack_require__(173); var IE_PROTO = __webpack_require__(96)('IE_PROTO'); var ObjectProto = Object.prototype; @@ -53248,12 +52929,12 @@ module.exports = Object.getPrototypeOf || function (O) { /***/ }), -/* 249 */ +/* 246 */ /***/ (function(module, exports, __webpack_require__) { var has = __webpack_require__(71); var toIObject = __webpack_require__(98); -var arrayIndexOf = __webpack_require__(236)(false); +var arrayIndexOf = __webpack_require__(233)(false); var IE_PROTO = __webpack_require__(96)('IE_PROTO'); module.exports = function (object, names) { @@ -53271,7 +52952,7 @@ module.exports = function (object, names) { /***/ }), -/* 250 */ +/* 247 */ /***/ (function(module, exports, __webpack_require__) { var hide = __webpack_require__(42); @@ -53284,14 +52965,14 @@ module.exports = function (target, src, safe) { /***/ }), -/* 251 */ +/* 248 */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__(42); /***/ }), -/* 252 */ +/* 249 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53299,8 +52980,8 @@ module.exports = __webpack_require__(42); var global = __webpack_require__(17); var core = __webpack_require__(31); var dP = __webpack_require__(72); -var DESCRIPTORS = __webpack_require__(51); -var SPECIES = __webpack_require__(20)('species'); +var DESCRIPTORS = __webpack_require__(52); +var SPECIES = __webpack_require__(21)('species'); module.exports = function (KEY) { var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY]; @@ -53312,7 +52993,7 @@ module.exports = function (KEY) { /***/ }), -/* 253 */ +/* 250 */ /***/ (function(module, exports, __webpack_require__) { var toInteger = __webpack_require__(97); @@ -53335,7 +53016,7 @@ module.exports = function (TO_STRING) { /***/ }), -/* 254 */ +/* 251 */ /***/ (function(module, exports, __webpack_require__) { var toInteger = __webpack_require__(97); @@ -53348,11 +53029,11 @@ module.exports = function (index, length) { /***/ }), -/* 255 */ +/* 252 */ /***/ (function(module, exports, __webpack_require__) { // 7.1.1 ToPrimitive(input [, PreferredType]) -var isObject = __webpack_require__(52); +var isObject = __webpack_require__(53); // instead of the ES6 spec version, we didn't implement @@toPrimitive case // and the second argument - flag - preferred type is a string module.exports = function (it, S) { @@ -53366,7 +53047,7 @@ module.exports = function (it, S) { /***/ }), -/* 256 */ +/* 253 */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(17); @@ -53376,12 +53057,12 @@ module.exports = navigator && navigator.userAgent || ''; /***/ }), -/* 257 */ +/* 254 */ /***/ (function(module, exports, __webpack_require__) { var classof = __webpack_require__(126); -var ITERATOR = __webpack_require__(20)('iterator'); -var Iterators = __webpack_require__(53); +var ITERATOR = __webpack_require__(21)('iterator'); +var Iterators = __webpack_require__(54); module.exports = __webpack_require__(31).getIteratorMethod = function (it) { if (it != undefined) return it[ITERATOR] || it['@@iterator'] @@ -53390,14 +53071,14 @@ module.exports = __webpack_require__(31).getIteratorMethod = function (it) { /***/ }), -/* 258 */ +/* 255 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var addToUnscopables = __webpack_require__(234); -var step = __webpack_require__(244); -var Iterators = __webpack_require__(53); +var addToUnscopables = __webpack_require__(231); +var step = __webpack_require__(241); +var Iterators = __webpack_require__(54); var toIObject = __webpack_require__(98); // 22.1.3.4 Array.prototype.entries() @@ -53431,13 +53112,13 @@ addToUnscopables('entries'); /***/ }), -/* 259 */ +/* 256 */ /***/ (function(module, exports) { /***/ }), -/* 260 */ +/* 257 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53447,16 +53128,16 @@ var global = __webpack_require__(17); var ctx = __webpack_require__(70); var classof = __webpack_require__(126); var $export = __webpack_require__(60); -var isObject = __webpack_require__(52); +var isObject = __webpack_require__(53); var aFunction = __webpack_require__(68); -var anInstance = __webpack_require__(235); -var forOf = __webpack_require__(237); +var anInstance = __webpack_require__(232); +var forOf = __webpack_require__(234); var speciesConstructor = __webpack_require__(134); var task = __webpack_require__(135).set; -var microtask = __webpack_require__(245)(); +var microtask = __webpack_require__(242)(); var newPromiseCapabilityModule = __webpack_require__(94); var perform = __webpack_require__(130); -var userAgent = __webpack_require__(256); +var userAgent = __webpack_require__(253); var promiseResolve = __webpack_require__(131); var PROMISE = 'Promise'; var TypeError = global.TypeError; @@ -53473,7 +53154,7 @@ var USE_NATIVE = !!function () { try { // correct subclassing with @@species support var promise = $Promise.resolve(1); - var FakePromise = (promise.constructor = {})[__webpack_require__(20)('species')] = function (exec) { + var FakePromise = (promise.constructor = {})[__webpack_require__(21)('species')] = function (exec) { exec(empty, empty); }; // unhandled rejections tracking support, NodeJS Promise without it fails @@species test @@ -53632,7 +53313,7 @@ if (!USE_NATIVE) { this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled this._n = false; // <- notify }; - Internal.prototype = __webpack_require__(250)($Promise.prototype, { + Internal.prototype = __webpack_require__(247)($Promise.prototype, { // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected) then: function then(onFulfilled, onRejected) { var reaction = newPromiseCapability(speciesConstructor(this, $Promise)); @@ -53664,7 +53345,7 @@ if (!USE_NATIVE) { $export($export.G + $export.W + $export.F * !USE_NATIVE, { Promise: $Promise }); __webpack_require__(95)($Promise, PROMISE); -__webpack_require__(252)(PROMISE); +__webpack_require__(249)(PROMISE); Wrapper = __webpack_require__(31)[PROMISE]; // statics @@ -53683,7 +53364,7 @@ $export($export.S + $export.F * (LIBRARY || !USE_NATIVE), PROMISE, { return promiseResolve(LIBRARY && this === Wrapper ? $Promise : this, x); } }); -$export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(243)(function (iter) { +$export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(240)(function (iter) { $Promise.all(iter)['catch'](empty); })), PROMISE, { // 25.4.4.1 Promise.all(iterable) @@ -53730,12 +53411,12 @@ $export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(243)(functio /***/ }), -/* 261 */ +/* 258 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var $at = __webpack_require__(253)(true); +var $at = __webpack_require__(250)(true); // 21.1.3.27 String.prototype[@@iterator]() __webpack_require__(129)(String, 'String', function (iterated) { @@ -53754,7 +53435,7 @@ __webpack_require__(129)(String, 'String', function (iterated) { /***/ }), -/* 262 */ +/* 259 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53781,7 +53462,7 @@ $export($export.P + $export.R, 'Promise', { 'finally': function (onFinally) { /***/ }), -/* 263 */ +/* 260 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53800,14 +53481,14 @@ $export($export.S, 'Promise', { 'try': function (callbackfn) { /***/ }), -/* 264 */ +/* 261 */ /***/ (function(module, exports, __webpack_require__) { -__webpack_require__(258); +__webpack_require__(255); var global = __webpack_require__(17); var hide = __webpack_require__(42); -var Iterators = __webpack_require__(53); -var TO_STRING_TAG = __webpack_require__(20)('toStringTag'); +var Iterators = __webpack_require__(54); +var TO_STRING_TAG = __webpack_require__(21)('toStringTag'); var DOMIterables = ('CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' + 'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' + @@ -53825,7 +53506,7 @@ for (var i = 0; i < DOMIterables.length; i++) { /***/ }), -/* 265 */ +/* 262 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -54026,7 +53707,7 @@ function localstorage() { /***/ }), -/* 266 */ +/* 263 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -54035,14 +53716,14 @@ function localstorage() { */ if (typeof process === 'undefined' || process.type === 'renderer') { - module.exports = __webpack_require__(265); + module.exports = __webpack_require__(262); } else { - module.exports = __webpack_require__(267); + module.exports = __webpack_require__(264); } /***/ }), -/* 267 */ +/* 264 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -54234,7 +53915,7 @@ exports.enable(load()); /***/ }), -/* 268 */ +/* 265 */ /***/ (function(module, exports, __webpack_require__) { (function webpackUniversalModuleDefinition(root, factory) { @@ -60948,7 +60629,7 @@ return /******/ (function(modules) { // webpackBootstrap ; /***/ }), -/* 269 */ +/* 266 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61072,12 +60753,12 @@ module.exports = function extend() { /***/ }), -/* 270 */ +/* 267 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const escapeStringRegexp = __webpack_require__(388); +const escapeStringRegexp = __webpack_require__(382); const platform = process.platform; @@ -61226,7 +60907,7 @@ module.exports = Object.assign(fn, figures); /***/ }), -/* 271 */ +/* 268 */ /***/ (function(module, exports, __webpack_require__) { // Copyright Joyent, Inc. and other Node contributors. @@ -61252,7 +60933,7 @@ module.exports = Object.assign(fn, figures); var pathModule = __webpack_require__(0); var isWindows = process.platform === 'win32'; -var fs = __webpack_require__(5); +var fs = __webpack_require__(4); // JavaScript implementation of realpath, ported from node pre-v6 @@ -61535,13 +61216,13 @@ exports.realpath = function realpath(p, cache, cb) { /***/ }), -/* 272 */ +/* 269 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync globSync.GlobSync = GlobSync -var fs = __webpack_require__(5) +var fs = __webpack_require__(4) var rp = __webpack_require__(140) var minimatch = __webpack_require__(82) var Minimatch = minimatch.Minimatch @@ -62026,6 +61707,387 @@ GlobSync.prototype._makeAbs = function (f) { } +/***/ }), +/* 270 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var resolve = __webpack_require__(271); + +module.exports = { + Validation: errorSubclass(ValidationError), + MissingRef: errorSubclass(MissingRefError) +}; + + +function ValidationError(errors) { + this.message = 'validation failed'; + this.errors = errors; + this.ajv = this.validation = true; +} + + +MissingRefError.message = function (baseId, ref) { + return 'can\'t resolve reference ' + ref + ' from id ' + baseId; +}; + + +function MissingRefError(baseId, ref, message) { + this.message = message || MissingRefError.message(baseId, ref); + this.missingRef = resolve.url(https://github.com/baseId,%20ref); + this.missingSchema = resolve.normalizeId(resolve.fullPath(this.missingRef)); +} + + +function errorSubclass(Subclass) { + Subclass.prototype = Object.create(Error.prototype); + Subclass.prototype.constructor = Subclass; + return Subclass; +} + + +/***/ }), +/* 271 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var url = __webpack_require__(24) + , equal = __webpack_require__(272) + , util = __webpack_require__(114) + , SchemaObject = __webpack_require__(386) + , traverse = __webpack_require__(677); + +module.exports = resolve; + +resolve.normalizeId = normalizeId; +resolve.fullPath = getFullPath; +resolve.url = resolveUrl; +resolve.ids = resolveIds; +resolve.inlineRef = inlineRef; +resolve.schema = resolveSchema; + +/** + * [resolve and compile the references ($ref)] + * @this Ajv + * @param {Function} compile reference to schema compilation funciton (localCompile) + * @param {Object} root object with information about the root schema for the current schema + * @param {String} ref reference to resolve + * @return {Object|Function} schema object (if the schema can be inlined) or validation function + */ +function resolve(compile, root, ref) { + /* jshint validthis: true */ + var refVal = this._refs[ref]; + if (typeof refVal == 'string') { + if (this._refs[refVal]) refVal = this._refs[refVal]; + else return resolve.call(this, compile, root, refVal); + } + + refVal = refVal || this._schemas[ref]; + if (refVal instanceof SchemaObject) { + return inlineRef(refVal.schema, this._opts.inlineRefs) + ? refVal.schema + : refVal.validate || this._compile(refVal); + } + + var res = resolveSchema.call(this, root, ref); + var schema, v, baseId; + if (res) { + schema = res.schema; + root = res.root; + baseId = res.baseId; + } + + if (schema instanceof SchemaObject) { + v = schema.validate || compile.call(this, schema.schema, root, undefined, baseId); + } else if (schema !== undefined) { + v = inlineRef(schema, this._opts.inlineRefs) + ? schema + : compile.call(this, schema, root, undefined, baseId); + } + + return v; +} + + +/** + * Resolve schema, its root and baseId + * @this Ajv + * @param {Object} root root object with properties schema, refVal, refs + * @param {String} ref reference to resolve + * @return {Object} object with properties schema, root, baseId + */ +function resolveSchema(root, ref) { + /* jshint validthis: true */ + var p = url.parse(ref, false, true) + , refPath = _getFullPath(p) + , baseId = getFullPath(this._getId(root.schema)); + if (refPath !== baseId) { + var id = normalizeId(refPath); + var refVal = this._refs[id]; + if (typeof refVal == 'string') { + return resolveRecursive.call(this, root, refVal, p); + } else if (refVal instanceof SchemaObject) { + if (!refVal.validate) this._compile(refVal); + root = refVal; + } else { + refVal = this._schemas[id]; + if (refVal instanceof SchemaObject) { + if (!refVal.validate) this._compile(refVal); + if (id == normalizeId(ref)) + return { schema: refVal, root: root, baseId: baseId }; + root = refVal; + } else { + return; + } + } + if (!root.schema) return; + baseId = getFullPath(this._getId(root.schema)); + } + return getJsonPointer.call(this, p, baseId, root.schema, root); +} + + +/* @this Ajv */ +function resolveRecursive(root, ref, parsedRef) { + /* jshint validthis: true */ + var res = resolveSchema.call(this, root, ref); + if (res) { + var schema = res.schema; + var baseId = res.baseId; + root = res.root; + var id = this._getId(schema); + if (id) baseId = resolveUrl(baseId, id); + return getJsonPointer.call(this, parsedRef, baseId, schema, root); + } +} + + +var PREVENT_SCOPE_CHANGE = util.toHash(['properties', 'patternProperties', 'enum', 'dependencies', 'definitions']); +/* @this Ajv */ +function getJsonPointer(parsedRef, baseId, schema, root) { + /* jshint validthis: true */ + parsedRef.hash = parsedRef.hash || ''; + if (parsedRef.hash.slice(0,2) != '#/') return; + var parts = parsedRef.hash.split('/'); + + for (var i = 1; i < parts.length; i++) { + var part = parts[i]; + if (part) { + part = util.unescapeFragment(part); + schema = schema[part]; + if (schema === undefined) break; + var id; + if (!PREVENT_SCOPE_CHANGE[part]) { + id = this._getId(schema); + if (id) baseId = resolveUrl(baseId, id); + if (schema.$ref) { + var $ref = resolveUrl(baseId, schema.$ref); + var res = resolveSchema.call(this, root, $ref); + if (res) { + schema = res.schema; + root = res.root; + baseId = res.baseId; + } + } + } + } + } + if (schema !== undefined && schema !== root.schema) + return { schema: schema, root: root, baseId: baseId }; +} + + +var SIMPLE_INLINED = util.toHash([ + 'type', 'format', 'pattern', + 'maxLength', 'minLength', + 'maxProperties', 'minProperties', + 'maxItems', 'minItems', + 'maximum', 'minimum', + 'uniqueItems', 'multipleOf', + 'required', 'enum' +]); +function inlineRef(schema, limit) { + if (limit === false) return false; + if (limit === undefined || limit === true) return checkNoRef(schema); + else if (limit) return countKeys(schema) <= limit; +} + + +function checkNoRef(schema) { + var item; + if (Array.isArray(schema)) { + for (var i=0; i', - $notOp = $isMax ? '>' : '<', - $errorKeyword = undefined; - if ($isDataExcl) { - var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr), - $exclusive = 'exclusive' + $lvl, - $exclType = 'exclType' + $lvl, - $exclIsNumber = 'exclIsNumber' + $lvl, - $opExpr = 'op' + $lvl, - $opStr = '\' + ' + $opExpr + ' + \''; - out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; '; - $schemaValueExcl = 'schemaExcl' + $lvl; - out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { '; - var $errorKeyword = $exclusiveKeyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\';'; - } else { - var $exclIsNumber = typeof $schemaExcl == 'number', - $opStr = $op; - if ($exclIsNumber && $isData) { - var $opExpr = '\'' + $opStr + '\''; - out += ' if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { '; - } else { - if ($exclIsNumber && $schema === undefined) { - $exclusive = true; - $errorKeyword = $exclusiveKeyword; - $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; - $schemaValue = $schemaExcl; - $notOp += '='; - } else { - if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); - if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) { - $exclusive = true; - $errorKeyword = $exclusiveKeyword; - $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; - $notOp += '='; - } else { - $exclusive = false; - $opStr += '='; - } - } - var $opExpr = '\'' + $opStr + '\''; - out += ' if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { '; - } - } - $errorKeyword = $errorKeyword || $keyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should be ' + ($opStr) + ' '; - if ($isData) { - out += '\' + ' + ($schemaValue); - } else { - out += '' + ($schemaValue) + '\''; - } - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - if ($breakOnError) { - out += ' else { '; - } - return out; -} - - -/***/ }), -/* 341 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = function generate__limitItems(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $errorKeyword; - var $data = 'data' + ($dataLvl || ''); - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - var $op = $keyword == 'maxItems' ? '>' : '<'; - out += 'if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { '; - var $errorKeyword = $keyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have '; - if ($keyword == 'maxItems') { - out += 'more'; - } else { - out += 'less'; - } - out += ' than '; - if ($isData) { - out += '\' + ' + ($schemaValue) + ' + \''; - } else { - out += '' + ($schema); - } - out += ' items\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += '} '; - if ($breakOnError) { - out += ' else { '; - } - return out; -} - - -/***/ }), -/* 342 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = function generate__limitLength(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $errorKeyword; - var $data = 'data' + ($dataLvl || ''); - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - var $op = $keyword == 'maxLength' ? '>' : '<'; - out += 'if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - if (it.opts.unicode === false) { - out += ' ' + ($data) + '.length '; - } else { - out += ' ucs2length(' + ($data) + ') '; - } - out += ' ' + ($op) + ' ' + ($schemaValue) + ') { '; - var $errorKeyword = $keyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT be '; - if ($keyword == 'maxLength') { - out += 'longer'; - } else { - out += 'shorter'; - } - out += ' than '; - if ($isData) { - out += '\' + ' + ($schemaValue) + ' + \''; - } else { - out += '' + ($schema); - } - out += ' characters\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += '} '; - if ($breakOnError) { - out += ' else { '; - } - return out; -} - - -/***/ }), -/* 343 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = function generate__limitProperties(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $errorKeyword; - var $data = 'data' + ($dataLvl || ''); - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - var $op = $keyword == 'maxProperties' ? '>' : '<'; - out += 'if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; - } - out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { '; - var $errorKeyword = $keyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have '; - if ($keyword == 'maxProperties') { - out += 'more'; - } else { - out += 'less'; - } - out += ' than '; - if ($isData) { - out += '\' + ' + ($schemaValue) + ' + \''; - } else { - out += '' + ($schema); - } - out += ' properties\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += '} '; - if ($breakOnError) { - out += ' else { '; - } - return out; -} - - -/***/ }), -/* 344 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = function generate_validate(it, $keyword, $ruleType) { - var out = ''; - var $async = it.schema.$async === true, - $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'), - $id = it.self._getId(it.schema); - if (it.isTop) { - if ($async) { - it.async = true; - var $es7 = it.opts.async == 'es7'; - it.yieldAwait = $es7 ? 'await' : 'yield'; - } - out += ' var validate = '; - if ($async) { - if ($es7) { - out += ' (async function '; - } else { - if (it.opts.async != '*') { - out += 'co.wrap'; - } - out += '(function* '; - } - } else { - out += ' (function '; - } - out += ' (data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; '; - if ($id && (it.opts.sourceCode || it.opts.processCode)) { - out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' '; - } - } - if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) { - var $keyword = 'false schema'; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $errorKeyword; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - if (it.schema === false) { - if (it.isTop) { - $breakOnError = true; - } else { - out += ' var ' + ($valid) + ' = false; '; - } - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'boolean schema is false\' '; - } - if (it.opts.verbose) { - out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - } else { - if (it.isTop) { - if ($async) { - out += ' return data; '; - } else { - out += ' validate.errors = null; return true; '; - } - } else { - out += ' var ' + ($valid) + ' = true; '; - } - } - if (it.isTop) { - out += ' }); return validate; '; - } - return out; - } - if (it.isTop) { - var $top = it.isTop, - $lvl = it.level = 0, - $dataLvl = it.dataLevel = 0, - $data = 'data'; - it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); - it.baseId = it.baseId || it.rootId; - delete it.isTop; - it.dataPathArr = [undefined]; - out += ' var vErrors = null; '; - out += ' var errors = 0; '; - out += ' if (rootData === undefined) rootData = data; '; - } else { - var $lvl = it.level, - $dataLvl = it.dataLevel, - $data = 'data' + ($dataLvl || ''); - if ($id) it.baseId = it.resolve.url(https://github.com/it.baseId,%20$id); - if ($async && !it.async) throw new Error('async schema in sync schema'); - out += ' var errs_' + ($lvl) + ' = errors;'; - } - var $valid = 'valid' + $lvl, - $breakOnError = !it.opts.allErrors, - $closingBraces1 = '', - $closingBraces2 = ''; - var $errorKeyword; - var $typeSchema = it.schema.type, - $typeIsArray = Array.isArray($typeSchema); - if ($typeIsArray && $typeSchema.length == 1) { - $typeSchema = $typeSchema[0]; - $typeIsArray = false; - } - if (it.schema.$ref && $refKeywords) { - if (it.opts.extendRefs == 'fail') { - throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); - } else if (it.opts.extendRefs !== true) { - $refKeywords = false; - it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); - } - } - if ($typeSchema) { - if (it.opts.coerceTypes) { - var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); - } - var $rulesGroup = it.RULES.types[$typeSchema]; - if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) { - var $schemaPath = it.schemaPath + '.type', - $errSchemaPath = it.errSchemaPath + '/type'; - var $schemaPath = it.schemaPath + '.type', - $errSchemaPath = it.errSchemaPath + '/type', - $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; - out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { '; - if ($coerceToTypes) { - var $dataType = 'dataType' + $lvl, - $coerced = 'coerced' + $lvl; - out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; '; - if (it.opts.coerceTypes == 'array') { - out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \'array\'; '; - } - out += ' var ' + ($coerced) + ' = undefined; '; - var $bracesCoercion = ''; - var arr1 = $coerceToTypes; - if (arr1) { - var $type, $i = -1, - l1 = arr1.length - 1; - while ($i < l1) { - $type = arr1[$i += 1]; - if ($i) { - out += ' if (' + ($coerced) + ' === undefined) { '; - $bracesCoercion += '}'; - } - if (it.opts.coerceTypes == 'array' && $type != 'array') { - out += ' if (' + ($dataType) + ' == \'array\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } '; - } - if ($type == 'string') { - out += ' if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; '; - } else if ($type == 'number' || $type == 'integer') { - out += ' if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' '; - if ($type == 'integer') { - out += ' && !(' + ($data) + ' % 1)'; - } - out += ')) ' + ($coerced) + ' = +' + ($data) + '; '; - } else if ($type == 'boolean') { - out += ' if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; '; - } else if ($type == 'null') { - out += ' if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; '; - } else if (it.opts.coerceTypes == 'array' && $type == 'array') { - out += ' if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; '; - } - } - } - out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should be '; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else { '; - var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', - $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; - out += ' ' + ($data) + ' = ' + ($coerced) + '; '; - if (!$dataLvl) { - out += 'if (' + ($parentData) + ' !== undefined)'; - } - out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } '; - } else { - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should be '; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - } - out += ' } '; - } - } - if (it.schema.$ref && !$refKeywords) { - out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' '; - if ($breakOnError) { - out += ' } if (errors === '; - if ($top) { - out += '0'; - } else { - out += 'errs_' + ($lvl); - } - out += ') { '; - $closingBraces2 += '}'; - } - } else { - if (it.opts.v5 && it.schema.patternGroups) { - it.logger.warn('keyword "patternGroups" is deprecated and disabled. Use option patternGroups: true to enable.'); - } - var arr2 = it.RULES; - if (arr2) { - var $rulesGroup, i2 = -1, - l2 = arr2.length - 1; - while (i2 < l2) { - $rulesGroup = arr2[i2 += 1]; - if ($shouldUseGroup($rulesGroup)) { - if ($rulesGroup.type) { - out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { '; - } - if (it.opts.useDefaults && !it.compositeRule) { - if ($rulesGroup.type == 'object' && it.schema.properties) { - var $schema = it.schema.properties, - $schemaKeys = Object.keys($schema); - var arr3 = $schemaKeys; - if (arr3) { - var $propertyKey, i3 = -1, - l3 = arr3.length - 1; - while (i3 < l3) { - $propertyKey = arr3[i3 += 1]; - var $sch = $schema[$propertyKey]; - if ($sch.default !== undefined) { - var $passData = $data + it.util.getProperty($propertyKey); - out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = '; - if (it.opts.useDefaults == 'shared') { - out += ' ' + (it.useDefault($sch.default)) + ' '; - } else { - out += ' ' + (JSON.stringify($sch.default)) + ' '; - } - out += '; '; - } - } - } - } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) { - var arr4 = it.schema.items; - if (arr4) { - var $sch, $i = -1, - l4 = arr4.length - 1; - while ($i < l4) { - $sch = arr4[$i += 1]; - if ($sch.default !== undefined) { - var $passData = $data + '[' + $i + ']'; - out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = '; - if (it.opts.useDefaults == 'shared') { - out += ' ' + (it.useDefault($sch.default)) + ' '; - } else { - out += ' ' + (JSON.stringify($sch.default)) + ' '; - } - out += '; '; - } - } - } - } - } - var arr5 = $rulesGroup.rules; - if (arr5) { - var $rule, i5 = -1, - l5 = arr5.length - 1; - while (i5 < l5) { - $rule = arr5[i5 += 1]; - if ($shouldUseRule($rule)) { - var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); - if ($code) { - out += ' ' + ($code) + ' '; - if ($breakOnError) { - $closingBraces1 += '}'; - } - } - } - } - } - if ($breakOnError) { - out += ' ' + ($closingBraces1) + ' '; - $closingBraces1 = ''; - } - if ($rulesGroup.type) { - out += ' } '; - if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) { - out += ' else { '; - var $schemaPath = it.schemaPath + '.type', - $errSchemaPath = it.errSchemaPath + '/type'; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should be '; - if ($typeIsArray) { - out += '' + ($typeSchema.join(",")); - } else { - out += '' + ($typeSchema); - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - } - } - if ($breakOnError) { - out += ' if (errors === '; - if ($top) { - out += '0'; - } else { - out += 'errs_' + ($lvl); - } - out += ') { '; - $closingBraces2 += '}'; - } - } - } - } - } - if ($breakOnError) { - out += ' ' + ($closingBraces2) + ' '; - } - if ($top) { - if ($async) { - out += ' if (errors === 0) return data; '; - out += ' else throw new ValidationError(vErrors); '; - } else { - out += ' validate.errors = vErrors; '; - out += ' return errors === 0; '; - } - out += ' }); return validate;'; - } else { - out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';'; - } - out = it.util.cleanUpCode(out); - if ($top) { - out = it.util.finalCleanUpCode(out, $async); - } - - function $shouldUseGroup($rulesGroup) { - var rules = $rulesGroup.rules; - for (var i = 0; i < rules.length; i++) - if ($shouldUseRule(rules[i])) return true; - } - - function $shouldUseRule($rule) { - return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule)); - } - - function $ruleImplementsSomeKeyword($rule) { - var impl = $rule.implements; - for (var i = 0; i < impl.length; i++) - if (it.schema[impl[i]] !== undefined) return true; - } - return out; -} - - -/***/ }), -/* 345 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(509)().Promise - - -/***/ }), -/* 346 */ /***/ (function(module, exports) { // API @@ -72226,10 +71397,10 @@ function clean(key) /***/ }), -/* 347 */ +/* 341 */ /***/ (function(module, exports, __webpack_require__) { -var defer = __webpack_require__(518); +var defer = __webpack_require__(486); // API module.exports = async; @@ -72266,11 +71437,11 @@ function async(callback) /***/ }), -/* 348 */ +/* 342 */ /***/ (function(module, exports, __webpack_require__) { -var async = __webpack_require__(347) - , abort = __webpack_require__(346) +var async = __webpack_require__(341) + , abort = __webpack_require__(340) ; // API @@ -72347,7 +71518,7 @@ function runJob(iterator, key, item, callback) /***/ }), -/* 349 */ +/* 343 */ /***/ (function(module, exports) { // API @@ -72390,11 +71561,11 @@ function state(list, sortMethod) /***/ }), -/* 350 */ +/* 344 */ /***/ (function(module, exports, __webpack_require__) { -var abort = __webpack_require__(346) - , async = __webpack_require__(347) +var abort = __webpack_require__(340) + , async = __webpack_require__(341) ; // API @@ -72425,12 +71596,12 @@ function terminator(callback) /***/ }), -/* 351 */ +/* 345 */ /***/ (function(module, exports, __webpack_require__) { -var iterate = __webpack_require__(348) - , initState = __webpack_require__(349) - , terminator = __webpack_require__(350) +var iterate = __webpack_require__(342) + , initState = __webpack_require__(343) + , terminator = __webpack_require__(344) ; // Public API @@ -72506,7 +71677,7 @@ function descending(a, b) /***/ }), -/* 352 */ +/* 346 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72521,7 +71692,7 @@ exports.default = { }; /***/ }), -/* 353 */ +/* 347 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72589,19 +71760,19 @@ exports.hasWrapper = hasWrapper; var _promise; function _load_promise() { - return _promise = __webpack_require__(50); + return _promise = __webpack_require__(51); } var _hoistedTreeBuilder; function _load_hoistedTreeBuilder() { - return _hoistedTreeBuilder = __webpack_require__(554); + return _hoistedTreeBuilder = __webpack_require__(522); } var _getTransitiveDevDependencies; function _load_getTransitiveDevDependencies() { - return _getTransitiveDevDependencies = __webpack_require__(580); + return _getTransitiveDevDependencies = __webpack_require__(548); } var _install; @@ -72624,7 +71795,7 @@ function _load_constants() { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -const zlib = __webpack_require__(198); +const zlib = __webpack_require__(199); const gzip = (0, (_promise || _load_promise()).promisify)(zlib.gzip); @@ -72838,7 +72009,7 @@ class Audit { exports.default = Audit; /***/ }), -/* 354 */ +/* 348 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73074,13 +72245,13 @@ exports.hasWrapper = hasWrapper; var _index; function _load_index() { - return _index = __webpack_require__(57); + return _index = __webpack_require__(58); } var _filter; function _load_filter() { - return _filter = __webpack_require__(372); + return _filter = __webpack_require__(366); } var _constants; @@ -73092,7 +72263,7 @@ function _load_constants() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -73165,7 +72336,7 @@ function hasWrapper(commander) { } /***/ }), -/* 355 */ +/* 349 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73365,7 +72536,7 @@ function _load_buildSubCommands() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -73374,7 +72545,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const invariant = __webpack_require__(9); const path = __webpack_require__(0); -const micromatch = __webpack_require__(114); +const micromatch = __webpack_require__(115); function hasWrapper(flags, args) { return args[0] !== 'dir'; @@ -73413,7 +72584,7 @@ function setFlags(commander) { } /***/ }), -/* 356 */ +/* 350 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73882,13 +73053,13 @@ function _load_errors() { var _integrityChecker; function _load_integrityChecker() { - return _integrityChecker = _interopRequireDefault(__webpack_require__(208)); + return _integrityChecker = _interopRequireDefault(__webpack_require__(206)); } var _integrityChecker2; function _load_integrityChecker2() { - return _integrityChecker2 = __webpack_require__(208); + return _integrityChecker2 = __webpack_require__(206); } var _lockfile; @@ -73900,7 +73071,7 @@ function _load_lockfile() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _install; @@ -73936,7 +73107,7 @@ function setFlags(commander) { } /***/ }), -/* 357 */ +/* 351 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74065,7 +73236,7 @@ function _load_errors() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _global; @@ -74080,7 +73251,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const invariant = __webpack_require__(9); -const cmdShim = __webpack_require__(201); +const cmdShim = __webpack_require__(202); const path = __webpack_require__(0); function hasWrapper(commander, args) { @@ -74092,7 +73263,7 @@ function setFlags(commander) { } /***/ }), -/* 358 */ +/* 352 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74365,7 +73536,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const invariant = __webpack_require__(9); -const micromatch = __webpack_require__(114); +const micromatch = __webpack_require__(115); const requireLockfile = exports.requireLockfile = true; @@ -74442,7 +73613,7 @@ function getDevDeps(manifest) { } /***/ }), -/* 359 */ +/* 353 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74456,7 +73627,7 @@ exports.run = exports.requireLockfile = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -74609,7 +73780,7 @@ function _load_lockfile() { var _index; function _load_index() { - return _index = __webpack_require__(57); + return _index = __webpack_require__(58); } var _install; @@ -74627,13 +73798,13 @@ function _load_errors() { var _index2; function _load_index2() { - return _index2 = __webpack_require__(200); + return _index2 = __webpack_require__(201); } var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _constants; @@ -74663,7 +73834,7 @@ function hasWrapper(commander, args) { } /***/ }), -/* 360 */ +/* 354 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74848,7 +74019,20 @@ let run = exports.run = (() => { } else { let suggestion; - for (const commandName in scripts) { + for (var _iterator9 = scripts.keys(), _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref16; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref16 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref16 = _i9.value; + } + + const commandName = _ref16; + const steps = leven(commandName, action); if (steps < 2) { suggestion = commandName; @@ -74933,19 +74117,19 @@ let run = exports.run = (() => { const printedCommands = new Map(); - for (var _iterator9 = pkgCommands, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { - var _ref16; + for (var _iterator10 = pkgCommands, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref17; - if (_isArray9) { - if (_i9 >= _iterator9.length) break; - _ref16 = _iterator9[_i9++]; + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref17 = _iterator10[_i10++]; } else { - _i9 = _iterator9.next(); - if (_i9.done) break; - _ref16 = _i9.value; + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref17 = _i10.value; } - const pkgCommand = _ref16; + const pkgCommand = _ref17; const action = scripts.get(pkgCommand); invariant(action, 'Action must exists'); @@ -74988,13 +74172,13 @@ function _load_executeLifecycleScript() { var _dynamicRequire; function _load_dynamicRequire() { - return _dynamicRequire = __webpack_require__(371); + return _dynamicRequire = __webpack_require__(365); } var _hooks; function _load_hooks() { - return _hooks = __webpack_require__(374); + return _hooks = __webpack_require__(368); } var _errors; @@ -75006,13 +74190,13 @@ function _load_errors() { var _packageCompatibility; function _load_packageCompatibility() { - return _packageCompatibility = __webpack_require__(209); + return _packageCompatibility = __webpack_require__(207); } var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _constants; @@ -75071,7 +74255,7 @@ function hasWrapper(commander, args) { } /***/ }), -/* 361 */ +/* 355 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75302,7 +74486,7 @@ exports.hasWrapper = hasWrapper; exports.examples = examples; /***/ }), -/* 362 */ +/* 356 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75316,7 +74500,7 @@ exports.run = exports.requireLockfile = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -75551,19 +74735,19 @@ function _load_add() { var _upgrade; function _load_upgrade() { - return _upgrade = __webpack_require__(207); + return _upgrade = __webpack_require__(205); } var _colorForVersions; function _load_colorForVersions() { - return _colorForVersions = _interopRequireDefault(__webpack_require__(369)); + return _colorForVersions = _interopRequireDefault(__webpack_require__(363)); } var _colorizeDiff; function _load_colorizeDiff() { - return _colorizeDiff = _interopRequireDefault(__webpack_require__(370)); + return _colorizeDiff = _interopRequireDefault(__webpack_require__(364)); } var _install; @@ -75593,7 +74777,7 @@ function hasWrapper(commander, args) { } /***/ }), -/* 363 */ +/* 357 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75813,7 +74997,7 @@ exports.hasWrapper = hasWrapper; var _index; function _load_index() { - return _index = __webpack_require__(57); + return _index = __webpack_require__(58); } var _executeLifecycleScript; @@ -75831,13 +75015,13 @@ function _load_errors() { var _gitSpawn; function _load_gitSpawn() { - return _gitSpawn = __webpack_require__(373); + return _gitSpawn = __webpack_require__(367); } var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _map; @@ -75880,7 +75064,7 @@ function hasWrapper(commander, args) { } /***/ }), -/* 364 */ +/* 358 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75894,7 +75078,7 @@ exports.LocalTarballFetcher = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -75924,7 +75108,7 @@ function _load_baseFetcher() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } var _misc; @@ -75945,11 +75129,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const crypto = __webpack_require__(11); const path = __webpack_require__(0); -const tarFs = __webpack_require__(193); +const tarFs = __webpack_require__(194); const url = __webpack_require__(24); -const fs = __webpack_require__(5); +const fs = __webpack_require__(4); const stream = __webpack_require__(23); -const gunzip = __webpack_require__(656); +const gunzip = __webpack_require__(624); const invariant = __webpack_require__(9); const ssri = __webpack_require__(65); @@ -76037,7 +75221,7 @@ class TarballFetcher extends (_baseFetcher || _load_baseFetcher()).default { const now = new Date(); - const fs = __webpack_require__(5); + const fs = __webpack_require__(4); const patchedFs = Object.assign({}, fs, { utimes: (path, atime, mtime, cb) => { fs.stat(path, (err, stat) => { @@ -76076,6 +75260,11 @@ class TarballFetcher extends (_baseFetcher || _load_baseFetcher()).default { chown: false, // don't chown. just leave as it is map: header => { header.mtime = now; + if (header.linkname) { + const basePath = path.posix.dirname(path.join('/', header.name)); + const jailPath = path.posix.join(basePath, header.linkname); + header.linkname = path.posix.relative('/', jailPath); + } return header; }, fs: patchedFs @@ -76319,7 +75508,7 @@ function urlParts(requestUrl) { } /***/ }), -/* 365 */ +/* 359 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76459,7 +75648,7 @@ class PackageReference { exports.default = PackageReference; /***/ }), -/* 366 */ +/* 360 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76496,7 +75685,7 @@ function _load_normalizePattern() { var _requestManager; function _load_requestManager() { - return _requestManager = _interopRequireDefault(__webpack_require__(378)); + return _requestManager = _interopRequireDefault(__webpack_require__(372)); } var _blockingQueue; @@ -76526,13 +75715,13 @@ function _load_workspaceLayout() { var _resolutionMap; function _load_resolutionMap() { - return _resolutionMap = _interopRequireDefault(__webpack_require__(214)); + return _resolutionMap = _interopRequireDefault(__webpack_require__(212)); } var _resolutionMap2; function _load_resolutionMap2() { - return _resolutionMap2 = __webpack_require__(214); + return _resolutionMap2 = __webpack_require__(212); } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -76609,7 +75798,7 @@ class PackageResolver { newPkg._remote = ref.remote; newPkg.name = oldPkg.name; newPkg.fresh = oldPkg.fresh; - newPkg.prebuilt2Variants = oldPkg.prebuilt2Variants; + newPkg.prebuiltVariants = oldPkg.prebuiltVariants; // update patterns for (var _iterator = ref.patterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { @@ -76663,7 +75852,7 @@ class PackageResolver { const pattern = _ref3; const oldPkg = this.patterns[pattern]; - newPkg.prebuilt2Variants = oldPkg.prebuilt2Variants; + newPkg.prebuiltVariants = oldPkg.prebuiltVariants; this.patterns[pattern] = newPkg; } @@ -77393,7 +76582,7 @@ class PackageResolver { exports.default = PackageResolver; /***/ }), -/* 367 */ +/* 361 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77452,7 +76641,7 @@ GitHubResolver.protocol = 'github'; GitHubResolver.hostname = 'github.com'; /***/ }), -/* 368 */ +/* 362 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77484,7 +76673,7 @@ function _load_misc() { var _fs; function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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; } } @@ -77532,7 +76721,7 @@ exports.default = LinkResolver; LinkResolver.protocol = 'link'; /***/ }), -/* 369 */ +/* 363 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77561,7 +76750,7 @@ function _load_semver() { var _semver2; function _load_semver2() { - return _semver2 = __webpack_require__(224); + return _semver2 = __webpack_require__(170); } var _constants; @@ -77573,7 +76762,7 @@ function _load_constants() { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /***/ }), -/* 370 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77597,7 +76786,7 @@ exports.default = function (from, to, reporter) { }; /***/ }), -/* 371 */ +/* 365 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77607,7 +76796,7 @@ exports.default = function (from, to, reporter) { exports.dynamicRequire = true ? require : require; // eslint-disable-line /***/ }), -/* 372 */ +/* 366 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77627,7 +76816,7 @@ function _load_misc() { return _misc = __webpack_require__(18); } -const mm = __webpack_require__(114); +const mm = __webpack_require__(115); const path = __webpack_require__(0); const WHITESPACE_RE = /^\s+$/; @@ -77849,7 +77038,7 @@ function filterOverridenGitignores(files) { } /***/ }), -/* 373 */ +/* 367 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77863,7 +77052,7 @@ exports.spawn = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _path; @@ -77875,7 +77064,7 @@ function _load_path() { var _child; function _load_child() { - return _child = _interopRequireWildcard(__webpack_require__(58)); + return _child = _interopRequireWildcard(__webpack_require__(50)); } 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; } } @@ -77907,7 +77096,7 @@ const spawn = exports.spawn = (args, opts = {}) => { }; /***/ }), -/* 374 */ +/* 368 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77940,7 +77129,7 @@ function callThroughHook(type, fn, context) { } /***/ }), -/* 375 */ +/* 369 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77968,7 +77157,7 @@ exports.default = key => { }; /***/ }), -/* 376 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77995,7 +77184,7 @@ function isValidPackagePath(input) { } /***/ }), -/* 377 */ +/* 371 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78029,7 +77218,7 @@ function resolveWithHome(path) { } /***/ }), -/* 378 */ +/* 372 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78042,7 +77231,7 @@ Object.defineProperty(exports, "__esModule", { var _fs; function _load_fs() { - return _fs = _interopRequireDefault(__webpack_require__(5)); + return _fs = _interopRequireDefault(__webpack_require__(4)); } var _http; @@ -78060,7 +77249,7 @@ function _load_url() { var _dnscache; function _load_dnscache() { - return _dnscache = _interopRequireDefault(__webpack_require__(637)); + return _dnscache = _interopRequireDefault(__webpack_require__(605)); } var _invariant; @@ -78409,6 +77598,11 @@ class RequestManager { rejectNext(err); }; + const rejectWithoutUrl = function rejectWithoutUrl(err) { + err.message = err.message; + rejectNext(err); + }; + const queueForRetry = reason => { const attempts = params.retryAttempts || 0; if (attempts >= this.maxRetryAttempts - 1) { @@ -78464,11 +77658,15 @@ class RequestManager { } } + if (res.statusCode === 401 && res.caseless && res.caseless.get('server') === 'GitHub.com') { + const message = `${res.body.message}. If using GITHUB_TOKEN in your env, check that it is valid.`; + rejectWithoutUrl(new Error(this.reporter.lang('unauthorizedResponse', res.caseless.get('server'), message))); + } + if (res.statusCode === 401 && res.headers['www-authenticate']) { const authMethods = res.headers['www-authenticate'].split(/,\s*/).map(s => s.toLowerCase()); - if (authMethods.indexOf('otp') !== -1) { - reject(new (_errors || _load_errors()).OneTimePasswordError()); + reject(new (_errors || _load_errors()).OneTimePasswordError(res.headers['npm-notice'])); return; } } @@ -78580,7 +77778,7 @@ class RequestManager { exports.default = RequestManager; /***/ }), -/* 379 */ +/* 373 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79143,11 +78341,11 @@ module.exports = { /***/ }), -/* 380 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { -var bufferFill = __webpack_require__(594) -var allocUnsafe = __webpack_require__(593) +var bufferFill = __webpack_require__(562) +var allocUnsafe = __webpack_require__(561) module.exports = function alloc (size, fill, encoding) { if (typeof size !== 'number') { @@ -79181,7 +78379,7 @@ module.exports = function alloc (size, fill, encoding) { /***/ }), -/* 381 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79227,7 +78425,7 @@ exports.toggle = (force, stream) => { /***/ }), -/* 382 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { var objectAssign = __webpack_require__(303); @@ -79537,7 +78735,7 @@ module.exports = { /***/ }), -/* 383 */ +/* 377 */ /***/ (function(module, exports) { @@ -79780,11 +78978,11 @@ function isObject(val) { /***/ }), -/* 384 */ +/* 378 */ /***/ (function(module, exports, __webpack_require__) { /* MIT license */ -var cssKeywords = __webpack_require__(610); +var cssKeywords = __webpack_require__(578); // NOTE: conversions should only return primitive values (i.e. arrays, or // values that give correct `typeof` results). @@ -80654,13 +79852,13 @@ convert.rgb.gray = function (rgb) { /***/ }), -/* 385 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { var util = __webpack_require__(3); var Stream = __webpack_require__(23).Stream; -var DelayedStream = __webpack_require__(634); -var defer = __webpack_require__(622); +var DelayedStream = __webpack_require__(602); +var defer = __webpack_require__(590); module.exports = CombinedStream; function CombinedStream() { @@ -80849,11 +80047,11 @@ CombinedStream.prototype._emitError = function(err) { /***/ }), -/* 386 */ +/* 380 */ /***/ (function(module, exports, __webpack_require__) { var stream = __webpack_require__(102) -var eos = __webpack_require__(173) +var eos = __webpack_require__(174) var inherits = __webpack_require__(61) var shift = __webpack_require__(942) @@ -81090,14 +80288,14 @@ module.exports = Duplexify /***/ }), -/* 387 */ +/* 381 */ /***/ (function(module, exports, __webpack_require__) { var crypto = __webpack_require__(11); var BigInteger = __webpack_require__(81).BigInteger; var ECPointFp = __webpack_require__(139).ECPointFp; var Buffer = __webpack_require__(15).Buffer; -exports.ECCurves = __webpack_require__(638); +exports.ECCurves = __webpack_require__(606); // zero prepad function unstupid(hex,len) @@ -81121,11 +80319,11 @@ exports.ECKey = function(curve, key, isPublic) // var y = key.slice(bytes+1); // this.P = new ECPointFp(curve, // curve.fromBigInteger(new BigInteger(x.toString("hex"), 16)), -// curve.fromBigInteger(new BigInteger(y.toString("hex"), 16))); +// curve.fromBigInteger(new BigInteger(y.toString("hex"), 16))); this.P = curve.decodePointHex(key.toString("hex")); }else{ if(key.length != bytes) return false; - priv = new BigInteger(key.toString("hex"), 16); + priv = new BigInteger(key.toString("hex"), 16); } }else{ var n1 = n.subtract(BigInteger.ONE); @@ -81147,14 +80345,14 @@ exports.ECKey = function(curve, key, isPublic) if(!key || !key.P) return false; var S = key.P.multiply(priv); return Buffer.from(unstupid(S.getX().toBigInteger().toString(16),bytes*2),"hex"); - } + } } } /***/ }), -/* 388 */ +/* 382 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81172,7 +80370,7 @@ module.exports = function (str) { /***/ }), -/* 389 */ +/* 383 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81238,13 +80436,13 @@ module.exports = function (data, opts) { /***/ }), -/* 390 */ +/* 384 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var fs = __webpack_require__(5) +var fs = __webpack_require__(4) module.exports = clone(fs) @@ -81266,12 +80464,12 @@ function clone (obj) { /***/ }), -/* 391 */ +/* 385 */ /***/ (function(module, exports, __webpack_require__) { -var fs = __webpack_require__(5) -var polyfills = __webpack_require__(655) -var legacy = __webpack_require__(654) +var fs = __webpack_require__(4) +var polyfills = __webpack_require__(623) +var legacy = __webpack_require__(622) var queue = [] var util = __webpack_require__(3) @@ -81295,7 +80493,7 @@ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { }) } -module.exports = patch(__webpack_require__(390)) +module.exports = patch(__webpack_require__(384)) if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { module.exports = patch(fs) } @@ -81533,6 +80731,897 @@ function retry () { } +/***/ }), +/* 386 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var util = __webpack_require__(114); + +module.exports = SchemaObject; + +function SchemaObject(obj) { + util.copy(obj, this); +} + + +/***/ }), +/* 387 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = function generate__limit(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $isMax = $keyword == 'maximum', + $exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum', + $schemaExcl = it.schema[$exclusiveKeyword], + $isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data, + $op = $isMax ? '<' : '>', + $notOp = $isMax ? '>' : '<', + $errorKeyword = undefined; + if ($isDataExcl) { + var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr), + $exclusive = 'exclusive' + $lvl, + $exclType = 'exclType' + $lvl, + $exclIsNumber = 'exclIsNumber' + $lvl, + $opExpr = 'op' + $lvl, + $opStr = '\' + ' + $opExpr + ' + \''; + out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; '; + $schemaValueExcl = 'schemaExcl' + $lvl; + out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { '; + var $errorKeyword = $exclusiveKeyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\';'; + } else { + var $exclIsNumber = typeof $schemaExcl == 'number', + $opStr = $op; + if ($exclIsNumber && $isData) { + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { '; + } else { + if ($exclIsNumber && $schema === undefined) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $schemaValue = $schemaExcl; + $notOp += '='; + } else { + if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); + if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) { + $exclusive = true; + $errorKeyword = $exclusiveKeyword; + $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword; + $notOp += '='; + } else { + $exclusive = false; + $opStr += '='; + } + } + var $opExpr = '\'' + $opStr + '\''; + out += ' if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { '; + } + } + $errorKeyword = $errorKeyword || $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be ' + ($opStr) + ' '; + if ($isData) { + out += '\' + ' + ($schemaValue); + } else { + out += '' + ($schemaValue) + '\''; + } + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + + +/***/ }), +/* 388 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = function generate__limitItems(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxItems' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxItems') { + out += 'more'; + } else { + out += 'less'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' items\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + + +/***/ }), +/* 389 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = function generate__limitLength(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxLength' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + if (it.opts.unicode === false) { + out += ' ' + ($data) + '.length '; + } else { + out += ' ucs2length(' + ($data) + ') '; + } + out += ' ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT be '; + if ($keyword == 'maxLength') { + out += 'longer'; + } else { + out += 'shorter'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' characters\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + + +/***/ }), +/* 390 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = function generate__limitProperties(it, $keyword, $ruleType) { + var out = ' '; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $isData = it.opts.$data && $schema && $schema.$data, + $schemaValue; + if ($isData) { + out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; + $schemaValue = 'schema' + $lvl; + } else { + $schemaValue = $schema; + } + var $op = $keyword == 'maxProperties' ? '>' : '<'; + out += 'if ( '; + if ($isData) { + out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || '; + } + out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { '; + var $errorKeyword = $keyword; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should NOT have '; + if ($keyword == 'maxProperties') { + out += 'more'; + } else { + out += 'less'; + } + out += ' than '; + if ($isData) { + out += '\' + ' + ($schemaValue) + ' + \''; + } else { + out += '' + ($schema); + } + out += ' properties\' '; + } + if (it.opts.verbose) { + out += ' , schema: '; + if ($isData) { + out += 'validate.schema' + ($schemaPath); + } else { + out += '' + ($schema); + } + out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += '} '; + if ($breakOnError) { + out += ' else { '; + } + return out; +} + + +/***/ }), +/* 391 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = function generate_validate(it, $keyword, $ruleType) { + var out = ''; + var $async = it.schema.$async === true, + $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'), + $id = it.self._getId(it.schema); + if (it.isTop) { + if ($async) { + it.async = true; + var $es7 = it.opts.async == 'es7'; + it.yieldAwait = $es7 ? 'await' : 'yield'; + } + out += ' var validate = '; + if ($async) { + if ($es7) { + out += ' (async function '; + } else { + if (it.opts.async != '*') { + out += 'co.wrap'; + } + out += '(function* '; + } + } else { + out += ' (function '; + } + out += ' (data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; '; + if ($id && (it.opts.sourceCode || it.opts.processCode)) { + out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' '; + } + } + if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) { + var $keyword = 'false schema'; + var $lvl = it.level; + var $dataLvl = it.dataLevel; + var $schema = it.schema[$keyword]; + var $schemaPath = it.schemaPath + it.util.getProperty($keyword); + var $errSchemaPath = it.errSchemaPath + '/' + $keyword; + var $breakOnError = !it.opts.allErrors; + var $errorKeyword; + var $data = 'data' + ($dataLvl || ''); + var $valid = 'valid' + $lvl; + if (it.schema === false) { + if (it.isTop) { + $breakOnError = true; + } else { + out += ' var ' + ($valid) + ' = false; '; + } + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; + if (it.opts.messages !== false) { + out += ' , message: \'boolean schema is false\' '; + } + if (it.opts.verbose) { + out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } else { + if (it.isTop) { + if ($async) { + out += ' return data; '; + } else { + out += ' validate.errors = null; return true; '; + } + } else { + out += ' var ' + ($valid) + ' = true; '; + } + } + if (it.isTop) { + out += ' }); return validate; '; + } + return out; + } + if (it.isTop) { + var $top = it.isTop, + $lvl = it.level = 0, + $dataLvl = it.dataLevel = 0, + $data = 'data'; + it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); + it.baseId = it.baseId || it.rootId; + delete it.isTop; + it.dataPathArr = [undefined]; + out += ' var vErrors = null; '; + out += ' var errors = 0; '; + out += ' if (rootData === undefined) rootData = data; '; + } else { + var $lvl = it.level, + $dataLvl = it.dataLevel, + $data = 'data' + ($dataLvl || ''); + if ($id) it.baseId = it.resolve.url(https://github.com/it.baseId,%20$id); + if ($async && !it.async) throw new Error('async schema in sync schema'); + out += ' var errs_' + ($lvl) + ' = errors;'; + } + var $valid = 'valid' + $lvl, + $breakOnError = !it.opts.allErrors, + $closingBraces1 = '', + $closingBraces2 = ''; + var $errorKeyword; + var $typeSchema = it.schema.type, + $typeIsArray = Array.isArray($typeSchema); + if ($typeIsArray && $typeSchema.length == 1) { + $typeSchema = $typeSchema[0]; + $typeIsArray = false; + } + if (it.schema.$ref && $refKeywords) { + if (it.opts.extendRefs == 'fail') { + throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); + } else if (it.opts.extendRefs !== true) { + $refKeywords = false; + it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); + } + } + if ($typeSchema) { + if (it.opts.coerceTypes) { + var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); + } + var $rulesGroup = it.RULES.types[$typeSchema]; + if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) { + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type', + $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; + out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { '; + if ($coerceToTypes) { + var $dataType = 'dataType' + $lvl, + $coerced = 'coerced' + $lvl; + out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; '; + if (it.opts.coerceTypes == 'array') { + out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \'array\'; '; + } + out += ' var ' + ($coerced) + ' = undefined; '; + var $bracesCoercion = ''; + var arr1 = $coerceToTypes; + if (arr1) { + var $type, $i = -1, + l1 = arr1.length - 1; + while ($i < l1) { + $type = arr1[$i += 1]; + if ($i) { + out += ' if (' + ($coerced) + ' === undefined) { '; + $bracesCoercion += '}'; + } + if (it.opts.coerceTypes == 'array' && $type != 'array') { + out += ' if (' + ($dataType) + ' == \'array\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } '; + } + if ($type == 'string') { + out += ' if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; '; + } else if ($type == 'number' || $type == 'integer') { + out += ' if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' '; + if ($type == 'integer') { + out += ' && !(' + ($data) + ' % 1)'; + } + out += ')) ' + ($coerced) + ' = +' + ($data) + '; '; + } else if ($type == 'boolean') { + out += ' if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; '; + } else if ($type == 'null') { + out += ' if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; '; + } else if (it.opts.coerceTypes == 'array' && $type == 'array') { + out += ' if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; '; + } + } + } + out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { '; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } else { '; + var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', + $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; + out += ' ' + ($data) + ' = ' + ($coerced) + '; '; + if (!$dataLvl) { + out += 'if (' + ($parentData) + ' !== undefined)'; + } + out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } '; + } else { + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + } + out += ' } '; + } + } + if (it.schema.$ref && !$refKeywords) { + out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' '; + if ($breakOnError) { + out += ' } if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } else { + if (it.opts.v5 && it.schema.patternGroups) { + it.logger.warn('keyword "patternGroups" is deprecated and disabled. Use option patternGroups: true to enable.'); + } + var arr2 = it.RULES; + if (arr2) { + var $rulesGroup, i2 = -1, + l2 = arr2.length - 1; + while (i2 < l2) { + $rulesGroup = arr2[i2 += 1]; + if ($shouldUseGroup($rulesGroup)) { + if ($rulesGroup.type) { + out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { '; + } + if (it.opts.useDefaults && !it.compositeRule) { + if ($rulesGroup.type == 'object' && it.schema.properties) { + var $schema = it.schema.properties, + $schemaKeys = Object.keys($schema); + var arr3 = $schemaKeys; + if (arr3) { + var $propertyKey, i3 = -1, + l3 = arr3.length - 1; + while (i3 < l3) { + $propertyKey = arr3[i3 += 1]; + var $sch = $schema[$propertyKey]; + if ($sch.default !== undefined) { + var $passData = $data + it.util.getProperty($propertyKey); + out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) { + var arr4 = it.schema.items; + if (arr4) { + var $sch, $i = -1, + l4 = arr4.length - 1; + while ($i < l4) { + $sch = arr4[$i += 1]; + if ($sch.default !== undefined) { + var $passData = $data + '[' + $i + ']'; + out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = '; + if (it.opts.useDefaults == 'shared') { + out += ' ' + (it.useDefault($sch.default)) + ' '; + } else { + out += ' ' + (JSON.stringify($sch.default)) + ' '; + } + out += '; '; + } + } + } + } + } + var arr5 = $rulesGroup.rules; + if (arr5) { + var $rule, i5 = -1, + l5 = arr5.length - 1; + while (i5 < l5) { + $rule = arr5[i5 += 1]; + if ($shouldUseRule($rule)) { + var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); + if ($code) { + out += ' ' + ($code) + ' '; + if ($breakOnError) { + $closingBraces1 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces1) + ' '; + $closingBraces1 = ''; + } + if ($rulesGroup.type) { + out += ' } '; + if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) { + out += ' else { '; + var $schemaPath = it.schemaPath + '.type', + $errSchemaPath = it.errSchemaPath + '/type'; + var $$outStack = $$outStack || []; + $$outStack.push(out); + out = ''; /* istanbul ignore else */ + if (it.createErrors !== false) { + out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' } '; + if (it.opts.messages !== false) { + out += ' , message: \'should be '; + if ($typeIsArray) { + out += '' + ($typeSchema.join(",")); + } else { + out += '' + ($typeSchema); + } + out += '\' '; + } + if (it.opts.verbose) { + out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + } + out += ' } '; + } else { + out += ' {} '; + } + var __err = out; + out = $$outStack.pop(); + if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ + if (it.async) { + out += ' throw new ValidationError([' + (__err) + ']); '; + } else { + out += ' validate.errors = [' + (__err) + ']; return false; '; + } + } else { + out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + } + out += ' } '; + } + } + if ($breakOnError) { + out += ' if (errors === '; + if ($top) { + out += '0'; + } else { + out += 'errs_' + ($lvl); + } + out += ') { '; + $closingBraces2 += '}'; + } + } + } + } + } + if ($breakOnError) { + out += ' ' + ($closingBraces2) + ' '; + } + if ($top) { + if ($async) { + out += ' if (errors === 0) return data; '; + out += ' else throw new ValidationError(vErrors); '; + } else { + out += ' validate.errors = vErrors; '; + out += ' return errors === 0; '; + } + out += ' }); return validate;'; + } else { + out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';'; + } + out = it.util.cleanUpCode(out); + if ($top) { + out = it.util.finalCleanUpCode(out, $async); + } + + function $shouldUseGroup($rulesGroup) { + var rules = $rulesGroup.rules; + for (var i = 0; i < rules.length; i++) + if ($shouldUseRule(rules[i])) return true; + } + + function $shouldUseRule($rule) { + return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule)); + } + + function $ruleImplementsSomeKeyword($rule) { + var impl = $rule.implements; + for (var i = 0; i < impl.length; i++) + if (it.schema[impl[i]] !== undefined) return true; + } + return out; +} + + /***/ }), /* 392 */ /***/ (function(module, exports, __webpack_require__) { @@ -81658,7 +81747,7 @@ module.exports = InputPrompt; var _ = __webpack_require__(38); var MuteStream = __webpack_require__(401); -var readline = __webpack_require__(197); +var readline = __webpack_require__(198); /** * Base interface class other can inherits from @@ -81745,7 +81834,7 @@ module.exports = UI; "use strict"; -var ansiEscapes = __webpack_require__(504); +var ansiEscapes = __webpack_require__(472); /** * Move cursor left by `x` @@ -81816,7 +81905,7 @@ module.exports = [["a140","",62],["a180","",32],["a240","î”Ļ",62],["a280", "use strict"; -module.exports = __webpack_require__(601).isCI +module.exports = __webpack_require__(569).isCI /***/ }), @@ -82672,7 +82761,7 @@ module.exports = { /**/ -var pna = __webpack_require__(180); +var pna = __webpack_require__(181); /**/ module.exports = Readable; @@ -82748,7 +82837,7 @@ function prependListener(emitter, event, fn) { } function ReadableState(options, stream) { - Duplex = Duplex || __webpack_require__(115); + Duplex = Duplex || __webpack_require__(116); options = options || {}; @@ -82825,7 +82914,7 @@ function ReadableState(options, stream) { } function Readable(options) { - Duplex = Duplex || __webpack_require__(115); + Duplex = Duplex || __webpack_require__(116); if (!(this instanceof Readable)) return new Readable(options); @@ -83739,7 +83828,7 @@ function indexOf(xs, x) { module.exports = Transform; -var Duplex = __webpack_require__(115); +var Duplex = __webpack_require__(116); /**/ var util = __webpack_require__(113); @@ -83921,7 +84010,7 @@ function done(stream, er, data) { /**/ -var pna = __webpack_require__(180); +var pna = __webpack_require__(181); /**/ module.exports = Writable; @@ -83992,7 +84081,7 @@ util.inherits(Writable, Stream); function nop() {} function WritableState(options, stream) { - Duplex = Duplex || __webpack_require__(115); + Duplex = Duplex || __webpack_require__(116); options = options || {}; @@ -84142,7 +84231,7 @@ if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.protot } function Writable(options) { - Duplex = Duplex || __webpack_require__(115); + Duplex = Duplex || __webpack_require__(116); // Writable ctor is applied to Duplexes, too. // `realHasInstance` is necessary because using plain `instanceof` @@ -84589,7 +84678,7 @@ Writable.prototype._destroy = function (err, cb) { /**/ -var pna = __webpack_require__(180); +var pna = __webpack_require__(181); /**/ // undocumented cb() API, needed for core, not for public API @@ -85070,7 +85159,7 @@ module.exports = function () { /***/ (function(module, exports, __webpack_require__) { var path = __webpack_require__(0); -var fs = __webpack_require__(5); +var fs = __webpack_require__(4); var parse = path.parse || __webpack_require__(774); module.exports = function nodeModulesPaths(start, opts) { @@ -85124,7 +85213,7 @@ module.exports = function nodeModulesPaths(start, opts) { /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return BehaviorSubject; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subject__ = __webpack_require__(36); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_ObjectUnsubscribedError__ = __webpack_require__(189); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_ObjectUnsubscribedError__ = __webpack_require__(190); /** PURE_IMPORTS_START tslib,_Subject,_util_ObjectUnsubscribedError PURE_IMPORTS_END */ @@ -85176,7 +85265,7 @@ var BehaviorSubject = /*@__PURE__*/ (function (_super) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return empty; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__config__ = __webpack_require__(185); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__config__ = __webpack_require__(186); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_hostReportError__ = __webpack_require__(323); /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */ @@ -85472,7 +85561,7 @@ function merge() { /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return NEVER; }); /* harmony export (immutable) */ __webpack_exports__["a"] = never; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Observable__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_noop__ = __webpack_require__(191); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_noop__ = __webpack_require__(192); /** PURE_IMPORTS_START _Observable,_util_noop PURE_IMPORTS_END */ @@ -85584,7 +85673,7 @@ var RaceSubscriber = /*@__PURE__*/ (function (_super) { /* harmony export (immutable) */ __webpack_exports__["a"] = timer; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Observable__ = __webpack_require__(12); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__scheduler_async__ = __webpack_require__(40); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isNumeric__ = __webpack_require__(190); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isNumeric__ = __webpack_require__(191); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_isScheduler__ = __webpack_require__(49); /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ @@ -85636,7 +85725,7 @@ function dispatch(state) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = audit; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_tryCatch__ = __webpack_require__(56); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_tryCatch__ = __webpack_require__(57); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_errorObject__ = __webpack_require__(48); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__OuterSubscriber__ = __webpack_require__(13); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_subscribeToResult__ = __webpack_require__(14); @@ -85749,7 +85838,7 @@ function concatMap(project, resultSelector) { /* harmony export (immutable) */ __webpack_exports__["a"] = distinctUntilChanged; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_tryCatch__ = __webpack_require__(56); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_tryCatch__ = __webpack_require__(57); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_errorObject__ = __webpack_require__(48); /** PURE_IMPORTS_START tslib,_Subscriber,_util_tryCatch,_util_errorObject PURE_IMPORTS_END */ @@ -86090,7 +86179,7 @@ var InnerRefCountSubscription = /*@__PURE__*/ (function (_super) { /* unused harmony export ObserveOnMessage */ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Notification__ = __webpack_require__(184); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Notification__ = __webpack_require__(185); /** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -86170,7 +86259,7 @@ var ObserveOnMessage = /*@__PURE__*/ (function () { /* harmony export (immutable) */ __webpack_exports__["a"] = tap; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_noop__ = __webpack_require__(191); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_noop__ = __webpack_require__(192); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_isFunction__ = __webpack_require__(154); /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ @@ -86566,7 +86655,7 @@ function isPromise(value) { /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__isPromise__ = __webpack_require__(445); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__isObject__ = __webpack_require__(444); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__symbol_iterator__ = __webpack_require__(151); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__symbol_observable__ = __webpack_require__(117); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__symbol_observable__ = __webpack_require__(118); /** PURE_IMPORTS_START _Observable,_subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */ @@ -86675,7 +86764,7 @@ var subscribeToIterable = function (iterable) { "use strict"; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return subscribeToObservable; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__symbol_observable__ = __webpack_require__(117); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__symbol_observable__ = __webpack_require__(118); /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */ var subscribeToObservable = function (obj) { @@ -87135,7 +87224,7 @@ var utils = __webpack_require__(26); var Key = __webpack_require__(27); var PrivateKey = __webpack_require__(33); -var sshpriv = __webpack_require__(192); +var sshpriv = __webpack_require__(193); /*JSSTYLED*/ var SSHKEY_RE = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/]+[=]*)([ \t]+([^ \t][^\n]*[\n]*)?)?$/; @@ -88280,7 +88369,7 @@ function simpleEnd(buf) { /***/ (function(module, exports, __webpack_require__) { var toBuffer = __webpack_require__(462) -var alloc = __webpack_require__(380) +var alloc = __webpack_require__(374) var ZEROS = '0000000000000000000' var SEVENS = '7777777777777777777' @@ -88590,7 +88679,7 @@ inherits(DestroyableTransform, Transform) DestroyableTransform.prototype.destroy = function(err) { if (this._destroyed) return this._destroyed = true - + var self = this process.nextTick(function() { if (err) @@ -88711,7 +88800,7 @@ function bytesToUuid(buf, offset) { var i = offset || 0; var bth = byteToHex; // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4 - return ([bth[buf[i++]], bth[buf[i++]], + return ([bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], '-', @@ -88790,7 +88879,7 @@ exports.default = handleSignals; var _child; function _load_child() { - return _child = __webpack_require__(58); + return _child = __webpack_require__(50); } function forwardSignalAndExit(signal) { @@ -88884,7 +88973,7 @@ module.exports = function (arg) { var util = __webpack_require__(3); var onExit = __webpack_require__(451); -var currentlyUnhandled = __webpack_require__(629); +var currentlyUnhandled = __webpack_require__(597); var installed = false; @@ -88926,7 +89015,7 @@ module.exports = function (log) { "use strict"; -const fs = __webpack_require__(391); +const fs = __webpack_require__(385); const path = __webpack_require__(0); const retry = __webpack_require__(819); const syncFs = __webpack_require__(779); @@ -89063,7 +89152,7 @@ threshold'), { code: 'ECOMPROMISED' })); // on process exit // We first check that `lock.updateTimeout.unref` exists because some users - // may be using this module outside of NodeJS (e.g., in an electron app), + // may be using this module outside of NodeJS (e.g., in an electron app), // and in those cases `setTimeout` return an integer. if (lock.updateTimeout.unref) { lock.updateTimeout.unref(); @@ -89312,2038 +89401,1417 @@ module.exports.checkSync = checkSync; "use strict"; +const x = module.exports; +const ESC = '\u001B['; +const OSC = '\u001B]'; +const BEL = '\u0007'; +const SEP = ';'; +const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal'; -var KEYWORDS = [ - 'multipleOf', - 'maximum', - 'exclusiveMaximum', - 'minimum', - 'exclusiveMinimum', - 'maxLength', - 'minLength', - 'pattern', - 'additionalItems', - 'maxItems', - 'minItems', - 'uniqueItems', - 'maxProperties', - 'minProperties', - 'required', - 'additionalProperties', - 'enum', - 'format', - 'const' -]; - -module.exports = function (metaSchema, keywordsJsonPointers) { - for (var i=0; i { + if (typeof x !== 'number') { + throw new TypeError('The `x` argument is required'); + } - for (j=0; j { + if (typeof x !== 'number') { + throw new TypeError('The `x` argument is required'); + } -/***/ }), -/* 473 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var compileSchema = __webpack_require__(478) - , resolve = __webpack_require__(203) - , Cache = __webpack_require__(474) - , SchemaObject = __webpack_require__(339) - , stableStringify = __webpack_require__(389) - , formats = __webpack_require__(477) - , rules = __webpack_require__(479) - , $dataMetaSchema = __webpack_require__(472) - , patternGroups = __webpack_require__(500) - , util = __webpack_require__(106) - , co = __webpack_require__(383); + let ret = ''; -module.exports = Ajv; + if (x < 0) { + ret += ESC + (-x) + 'D'; + } else if (x > 0) { + ret += ESC + x + 'C'; + } -Ajv.prototype.validate = validate; -Ajv.prototype.compile = compile; -Ajv.prototype.addSchema = addSchema; -Ajv.prototype.addMetaSchema = addMetaSchema; -Ajv.prototype.validateSchema = validateSchema; -Ajv.prototype.getSchema = getSchema; -Ajv.prototype.removeSchema = removeSchema; -Ajv.prototype.addFormat = addFormat; -Ajv.prototype.errorsText = errorsText; + if (y < 0) { + ret += ESC + (-y) + 'A'; + } else if (y > 0) { + ret += ESC + y + 'B'; + } -Ajv.prototype._addSchema = _addSchema; -Ajv.prototype._compile = _compile; + return ret; +}; -Ajv.prototype.compileAsync = __webpack_require__(476); -var customKeyword = __webpack_require__(499); -Ajv.prototype.addKeyword = customKeyword.add; -Ajv.prototype.getKeyword = customKeyword.get; -Ajv.prototype.removeKeyword = customKeyword.remove; +x.cursorUp = count => ESC + (typeof count === 'number' ? count : 1) + 'A'; +x.cursorDown = count => ESC + (typeof count === 'number' ? count : 1) + 'B'; +x.cursorForward = count => ESC + (typeof count === 'number' ? count : 1) + 'C'; +x.cursorBackward = count => ESC + (typeof count === 'number' ? count : 1) + 'D'; -var errorClasses = __webpack_require__(202); -Ajv.ValidationError = errorClasses.Validation; -Ajv.MissingRefError = errorClasses.MissingRef; -Ajv.$dataMetaSchema = $dataMetaSchema; +x.cursorLeft = ESC + 'G'; +x.cursorSavePosition = ESC + (isTerminalApp ? '7' : 's'); +x.cursorRestorePosition = ESC + (isTerminalApp ? '8' : 'u'); +x.cursorGetPosition = ESC + '6n'; +x.cursorNextLine = ESC + 'E'; +x.cursorPrevLine = ESC + 'F'; +x.cursorHide = ESC + '?25l'; +x.cursorShow = ESC + '?25h'; -var META_SCHEMA_ID = 'http://json-schema.org/draft-06/schema'; +x.eraseLines = count => { + let clear = ''; -var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes' ]; -var META_SUPPORT_DATA = ['/properties']; + for (let i = 0; i < count; i++) { + clear += x.eraseLine + (i < count - 1 ? x.cursorUp() : ''); + } -/** - * Creates validator instance. - * Usage: `Ajv(opts)` - * @param {Object} opts optional options - * @return {Object} ajv instance - */ -function Ajv(opts) { - if (!(this instanceof Ajv)) return new Ajv(opts); - opts = this._opts = util.copy(opts) || {}; - setLogger(this); - this._schemas = {}; - this._refs = {}; - this._fragments = {}; - this._formats = formats(opts.format); - var schemaUriFormat = this._schemaUriFormat = this._formats['uri-reference']; - this._schemaUriFormatFunc = function (str) { return schemaUriFormat.test(str); }; + if (count) { + clear += x.cursorLeft; + } - this._cache = opts.cache || new Cache; - this._loadingSchemas = {}; - this._compilations = []; - this.RULES = rules(); - this._getId = chooseGetId(opts); + return clear; +}; - opts.loopRequired = opts.loopRequired || Infinity; - if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true; - if (opts.serialize === undefined) opts.serialize = stableStringify; - this._metaOpts = getMetaSchemaOptions(this); +x.eraseEndLine = ESC + 'K'; +x.eraseStartLine = ESC + '1K'; +x.eraseLine = ESC + '2K'; +x.eraseDown = ESC + 'J'; +x.eraseUp = ESC + '1J'; +x.eraseScreen = ESC + '2J'; +x.scrollUp = ESC + 'S'; +x.scrollDown = ESC + 'T'; - if (opts.formats) addInitialFormats(this); - addDraft6MetaSchema(this); - if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta); - addInitialSchemas(this); - if (opts.patternGroups) patternGroups(this); -} +x.clearScreen = '\u001Bc'; +x.beep = BEL; +x.link = (text, url) => { + return [ + OSC, + '8', + SEP, + SEP, + url, + BEL, + text, + OSC, + '8', + SEP, + SEP, + BEL + ].join(''); +}; +x.image = (buf, opts) => { + opts = opts || {}; -/** - * Validate data using schema - * Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize. - * @this Ajv - * @param {String|Object} schemaKeyRef key, ref or schema object - * @param {Any} data to be validated - * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). - */ -function validate(schemaKeyRef, data) { - var v; - if (typeof schemaKeyRef == 'string') { - v = this.getSchema(schemaKeyRef); - if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"'); - } else { - var schemaObj = this._addSchema(schemaKeyRef); - v = schemaObj.validate || this._compile(schemaObj); - } + let ret = OSC + '1337;File=inline=1'; - var valid = v(data); - if (v.$async === true) - return this._opts.async == '*' ? co(valid) : valid; - this.errors = v.errors; - return valid; -} + if (opts.width) { + ret += `;width=${opts.width}`; + } + if (opts.height) { + ret += `;height=${opts.height}`; + } -/** - * Create validating function for passed schema. - * @this Ajv - * @param {Object} schema schema object - * @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords. - * @return {Function} validating function - */ -function compile(schema, _meta) { - var schemaObj = this._addSchema(schema, undefined, _meta); - return schemaObj.validate || this._compile(schemaObj); -} + if (opts.preserveAspectRatio === false) { + ret += ';preserveAspectRatio=0'; + } + return ret + ':' + buf.toString('base64') + BEL; +}; -/** - * Adds schema to the instance. - * @this Ajv - * @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. - * @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. - * @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead. - * @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead. - * @return {Ajv} this for method chaining - */ -function addSchema(schema, key, _skipValidation, _meta) { - if (Array.isArray(schema)){ - for (var i=0; i OSC + '50;CurrentDir=' + (cwd || process.cwd()) + BEL; -/** - * Add schema that will be used to validate other schemas - * options in META_IGNORE_OPTIONS are alway set to false - * @this Ajv - * @param {Object} schema schema object - * @param {String} key optional schema key - * @param {Boolean} skipValidation true to skip schema validation, can be used to override validateSchema option for meta-schema - * @return {Ajv} this for method chaining - */ -function addMetaSchema(schema, key, skipValidation) { - this.addSchema(schema, key, skipValidation, true); - return this; -} +/***/ }), +/* 473 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Validate schema - * @this Ajv - * @param {Object} schema schema to validate - * @param {Boolean} throwOrLogError pass true to throw (or log) an error if invalid - * @return {Boolean} true if schema is valid - */ -function validateSchema(schema, throwOrLogError) { - var $schema = schema.$schema; - if ($schema !== undefined && typeof $schema != 'string') - throw new Error('$schema must be a string'); - $schema = $schema || this._opts.defaultMeta || defaultMeta(this); - if (!$schema) { - this.logger.warn('meta-schema not available'); - this.errors = null; - return true; - } - var currentUriFormat = this._formats.uri; - this._formats.uri = typeof currentUriFormat == 'function' - ? this._schemaUriFormatFunc - : this._schemaUriFormat; - var valid; - try { valid = this.validate($schema, schema); } - finally { this._formats.uri = currentUriFormat; } - if (!valid && throwOrLogError) { - var message = 'schema is invalid: ' + this.errorsText(); - if (this._opts.validateSchema == 'log') this.logger.error(message); - else throw new Error(message); - } - return valid; -} +"use strict"; +module.exports = function () { + return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g; +}; -function defaultMeta(self) { - var meta = self._opts.meta; - self._opts.defaultMeta = typeof meta == 'object' - ? self._getId(meta) || meta - : self.getSchema(META_SCHEMA_ID) - ? META_SCHEMA_ID - : undefined; - return self._opts.defaultMeta; -} +/***/ }), +/* 474 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Get compiled schema from the instance by `key` or `ref`. - * @this Ajv - * @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id). - * @return {Function} schema validating function (with property `schema`). - */ -function getSchema(keyRef) { - var schemaObj = _getSchemaObj(this, keyRef); - switch (typeof schemaObj) { - case 'object': return schemaObj.validate || this._compile(schemaObj); - case 'string': return this.getSchema(schemaObj); - case 'undefined': return _getSchemaFragment(this, keyRef); - } -} +"use strict"; +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(576); +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; -function _getSchemaFragment(self, ref) { - var res = resolve.schema.call(self, { schema: {} }, ref); - if (res) { - var schema = res.schema - , root = res.root - , baseId = res.baseId; - var v = compileSchema.call(self, schema, root, undefined, baseId); - self._fragments[ref] = new SchemaObject({ - ref: ref, - fragment: true, - schema: schema, - root: root, - baseId: baseId, - validate: v - }); - return v; - } -} +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; +const wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; -function _getSchemaObj(self, keyRef) { - keyRef = resolve.normalizeId(keyRef); - return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef]; -} +function assembleStyles() { + const codes = new Map(); + const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39], + // Bright color + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39] + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], -/** - * Remove cached schema(s). - * If no parameter is passed all schemas but meta-schemas are removed. - * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. - * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. - * @this Ajv - * @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object - * @return {Ajv} this for method chaining - */ -function removeSchema(schemaKeyRef) { - if (schemaKeyRef instanceof RegExp) { - _removeAllSchemas(this, this._schemas, schemaKeyRef); - _removeAllSchemas(this, this._refs, schemaKeyRef); - return this; - } - switch (typeof schemaKeyRef) { - case 'undefined': - _removeAllSchemas(this, this._schemas); - _removeAllSchemas(this, this._refs); - this._cache.clear(); - return this; - case 'string': - var schemaObj = _getSchemaObj(this, schemaKeyRef); - if (schemaObj) this._cache.del(schemaObj.cacheKey); - delete this._schemas[schemaKeyRef]; - delete this._refs[schemaKeyRef]; - return this; - case 'object': - var serialize = this._opts.serialize; - var cacheKey = serialize ? serialize(schemaKeyRef) : schemaKeyRef; - this._cache.del(cacheKey); - var id = this._getId(schemaKeyRef); - if (id) { - id = resolve.normalizeId(id); - delete this._schemas[id]; - delete this._refs[id]; - } - } - return this; -} + // Bright color + bgBlackBright: [100, 49], + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49] + } + }; + // Fix humans + styles.color.grey = styles.color.gray; -function _removeAllSchemas(self, schemas, regex) { - for (var keyRef in schemas) { - var schemaObj = schemas[keyRef]; - if (!schemaObj.meta && (!regex || regex.test(keyRef))) { - self._cache.del(schemaObj.cacheKey); - delete schemas[keyRef]; - } - } -} + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; + for (const styleName of Object.keys(group)) { + const style = group[styleName]; -/* @this Ajv */ -function _addSchema(schema, skipValidation, meta, shouldAddSchema) { - if (typeof schema != 'object' && typeof schema != 'boolean') - throw new Error('schema should be object or boolean'); - var serialize = this._opts.serialize; - var cacheKey = serialize ? serialize(schema) : schema; - var cached = this._cache.get(cacheKey); - if (cached) return cached; + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; - shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false; + group[styleName] = styles[styleName]; - var id = resolve.normalizeId(this._getId(schema)); - if (id && shouldAddSchema) checkUnique(this, id); + codes.set(style[0], style[1]); + } - var willValidate = this._opts.validateSchema !== false && !skipValidation; - var recursiveMeta; - if (willValidate && !(recursiveMeta = id && id == resolve.normalizeId(schema.$schema))) - this.validateSchema(schema, true); + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); - var localRefs = resolve.ids.call(this, schema); + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + } - var schemaObj = new SchemaObject({ - id: id, - schema: schema, - localRefs: localRefs, - cacheKey: cacheKey, - meta: meta - }); + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; - if (id[0] != '#' && shouldAddSchema) this._refs[id] = schemaObj; - this._cache.put(cacheKey, schemaObj); + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; - if (willValidate && recursiveMeta) this.validateSchema(schema, true); + styles.color.ansi = { + ansi: wrapAnsi16(ansi2ansi, 0) + }; + styles.color.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 0) + }; + styles.color.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 0) + }; - return schemaObj; -} + styles.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { + continue; + } -/* @this Ajv */ -function _compile(schemaObj, root) { - if (schemaObj.compiling) { - schemaObj.validate = callValidate; - callValidate.schema = schemaObj.schema; - callValidate.errors = null; - callValidate.root = root ? root : callValidate; - if (schemaObj.schema.$async === true) - callValidate.$async = true; - return callValidate; - } - schemaObj.compiling = true; + const suite = colorConvert[key]; - var currentOpts; - if (schemaObj.meta) { - currentOpts = this._opts; - this._opts = this._metaOpts; - } + if (key === 'ansi16') { + key = 'ansi'; + } - var v; - try { v = compileSchema.call(this, schemaObj.schema, root, schemaObj.localRefs); } - finally { - schemaObj.compiling = false; - if (schemaObj.meta) this._opts = currentOpts; - } + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } - schemaObj.validate = v; - schemaObj.refs = v.refs; - schemaObj.refVal = v.refVal; - schemaObj.root = v.root; - return v; + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } - function callValidate() { - var _validate = schemaObj.validate; - var result = _validate.apply(null, arguments); - callValidate.errors = _validate.errors; - return result; - } + return styles; } +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); -function chooseGetId(opts) { - switch (opts.schemaId) { - case '$id': return _get$Id; - case 'id': return _getId; - default: return _get$IdOrId; - } -} +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(163)(module))) -/* @this Ajv */ -function _getId(schema) { - if (schema.$id) this.logger.warn('schema $id ignored', schema.$id); - return schema.id; -} +/***/ }), +/* 475 */ +/***/ (function(module, exports) { -/* @this Ajv */ -function _get$Id(schema) { - if (schema.id) this.logger.warn('schema id ignored', schema.id); - return schema.$id; +function webpackEmptyContext(req) { + throw new Error("Cannot find module '" + req + "'."); } +webpackEmptyContext.keys = function() { return []; }; +webpackEmptyContext.resolve = webpackEmptyContext; +module.exports = webpackEmptyContext; +webpackEmptyContext.id = 475; +/***/ }), +/* 476 */ +/***/ (function(module, exports, __webpack_require__) { -function _get$IdOrId(schema) { - if (schema.$id && schema.id && schema.$id != schema.id) - throw new Error('schema $id is different from id'); - return schema.$id || schema.id; -} +"use strict"; + // global key for user preferred registration +var REGISTRATION_KEY = '@@any-promise/REGISTRATION', + // Prior registration (preferred or detected) + registered = null /** - * Convert array of error message objects to string - * @this Ajv - * @param {Array} errors optional array of validation errors, if not passed errors from the instance are used. - * @param {Object} options optional options with properties `separator` and `dataVar`. - * @return {String} human readable string with all errors descriptions + * Registers the given implementation. An implementation must + * be registered prior to any call to `require("any-promise")`, + * typically on application load. + * + * If called with no arguments, will return registration in + * following priority: + * + * For Node.js: + * + * 1. Previous registration + * 2. global.Promise if node.js version >= 0.12 + * 3. Auto detected promise based on first sucessful require of + * known promise libraries. Note this is a last resort, as the + * loaded library is non-deterministic. node.js >= 0.12 will + * always use global.Promise over this priority list. + * 4. Throws error. + * + * For Browser: + * + * 1. Previous registration + * 2. window.Promise + * 3. Throws error. + * + * Options: + * + * Promise: Desired Promise constructor + * global: Boolean - Should the registration be cached in a global variable to + * allow cross dependency/bundle registration? (default true) */ -function errorsText(errors, options) { - errors = errors || this.errors; - if (!errors) return 'No errors'; - options = options || {}; - var separator = options.separator === undefined ? ', ' : options.separator; - var dataVar = options.dataVar === undefined ? 'data' : options.dataVar; +module.exports = function(root, loadImplementation){ + return function register(implementation, opts){ + implementation = implementation || null + opts = opts || {} + // global registration unless explicitly {global: false} in options (default true) + var registerGlobal = opts.global !== false; - var text = ''; - for (var i=0; i + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ -var Cache = module.exports = function Cache() { - this._cache = {}; -}; - - -Cache.prototype.put = function Cache_put(key, value) { - this._cache[key] = value; +module.exports = function (arr) { + return flat(arr, []); }; - -Cache.prototype.get = function Cache_get(key) { - return this._cache[key]; -}; +function flat(arr, res) { + var i = 0, cur; + var len = arr.length; + for (; i < len; i++) { + cur = arr[i]; + Array.isArray(cur) ? flat(cur, res) : res.push(cur); + } + return res; +} -Cache.prototype.del = function Cache_del(key) { - delete this._cache[key]; -}; +/***/ }), +/* 479 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; -Cache.prototype.clear = function Cache_clear() { - this._cache = {}; -}; +module.exports = function (arr, predicate, ctx) { + if (typeof Array.prototype.findIndex === 'function') { + return arr.findIndex(predicate, ctx); + } + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } -/***/ }), -/* 475 */ -/***/ (function(module, exports, __webpack_require__) { + var list = Object(arr); + var len = list.length; -"use strict"; + if (len === 0) { + return -1; + } + for (var i = 0; i < len; i++) { + if (predicate.call(ctx, list[i], i, list)) { + return i; + } + } -//all requires must be explicit because browserify won't work with dynamic requires -module.exports = { - '$ref': __webpack_require__(496), - allOf: __webpack_require__(481), - anyOf: __webpack_require__(482), - const: __webpack_require__(483), - contains: __webpack_require__(484), - dependencies: __webpack_require__(486), - 'enum': __webpack_require__(487), - format: __webpack_require__(488), - items: __webpack_require__(489), - maximum: __webpack_require__(340), - minimum: __webpack_require__(340), - maxItems: __webpack_require__(341), - minItems: __webpack_require__(341), - maxLength: __webpack_require__(342), - minLength: __webpack_require__(342), - maxProperties: __webpack_require__(343), - minProperties: __webpack_require__(343), - multipleOf: __webpack_require__(490), - not: __webpack_require__(491), - oneOf: __webpack_require__(492), - pattern: __webpack_require__(493), - properties: __webpack_require__(494), - propertyNames: __webpack_require__(495), - required: __webpack_require__(497), - uniqueItems: __webpack_require__(498), - validate: __webpack_require__(344) + return -1; }; /***/ }), -/* 476 */ +/* 480 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var MissingRefError = __webpack_require__(202).MissingRef; - -module.exports = compileAsync; - +var rawAsap = __webpack_require__(481); +var freeTasks = []; /** - * Creates validating function for passed schema with asynchronous loading of missing schemas. - * `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema. - * @this Ajv - * @param {Object} schema schema object - * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped - * @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function. - * @return {Promise} promise that resolves with a validating function. + * Calls a task as soon as possible after returning, in its own event, with + * priority over IO events. An exception thrown in a task can be handled by + * `process.on("uncaughtException") or `domain.on("error")`, but will otherwise + * crash the process. If the error is handled, all subsequent tasks will + * resume. + * + * @param {{call}} task A callable object, typically a function that takes no + * arguments. */ -function compileAsync(schema, meta, callback) { - /* eslint no-shadow: 0 */ - /* global Promise */ - /* jshint validthis: true */ - var self = this; - if (typeof this._opts.loadSchema != 'function') - throw new Error('options.loadSchema should be a function'); +module.exports = asap; +function asap(task) { + var rawTask; + if (freeTasks.length) { + rawTask = freeTasks.pop(); + } else { + rawTask = new RawTask(); + } + rawTask.task = task; + rawTask.domain = process.domain; + rawAsap(rawTask); +} - if (typeof meta == 'function') { - callback = meta; - meta = undefined; - } +function RawTask() { + this.task = null; + this.domain = null; +} - var p = loadMetaSchemaOf(schema).then(function () { - var schemaObj = self._addSchema(schema, undefined, meta); - return schemaObj.validate || _compileAsync(schemaObj); - }); +RawTask.prototype.call = function () { + if (this.domain) { + this.domain.enter(); + } + var threw = true; + try { + this.task.call(); + threw = false; + // If the task throws an exception (presumably) Node.js restores the + // domain stack for the next event. + if (this.domain) { + this.domain.exit(); + } + } finally { + // We use try/finally and a threw flag to avoid messing up stack traces + // when we catch and release errors. + if (threw) { + // In Node.js, uncaught exceptions are considered fatal errors. + // Re-throw them to interrupt flushing! + // Ensure that flushing continues if an uncaught exception is + // suppressed listening process.on("uncaughtException") or + // domain.on("error"). + rawAsap.requestFlush(); + } + // If the task threw an error, we do not want to exit the domain here. + // Exiting the domain would prevent the domain from catching the error. + this.task = null; + this.domain = null; + freeTasks.push(this); + } +}; - if (callback) { - p.then( - function(v) { callback(null, v); }, - callback - ); - } - return p; +/***/ }), +/* 481 */ +/***/ (function(module, exports, __webpack_require__) { - function loadMetaSchemaOf(sch) { - var $schema = sch.$schema; - return $schema && !self.getSchema($schema) - ? compileAsync.call(self, { $ref: $schema }, true) - : Promise.resolve(); - } +"use strict"; - function _compileAsync(schemaObj) { - try { return self._compile(schemaObj); } - catch(e) { - if (e instanceof MissingRefError) return loadMissingSchema(e); - throw e; - } +var domain; // The domain module is executed on demand +var hasSetImmediate = typeof setImmediate === "function"; +// Use the fastest means possible to execute a task in its own turn, with +// priority over other events including network IO events in Node.js. +// +// An exception thrown by a task will permanently interrupt the processing of +// subsequent tasks. The higher level `asap` function ensures that if an +// exception is thrown by a task, that the task queue will continue flushing as +// soon as possible, but if you use `rawAsap` directly, you are responsible to +// either ensure that no exceptions are thrown from your task, or to manually +// call `rawAsap.requestFlush` if an exception is thrown. +module.exports = rawAsap; +function rawAsap(task) { + if (!queue.length) { + requestFlush(); + flushing = true; + } + // Avoids a function call + queue[queue.length] = task; +} - function loadMissingSchema(e) { - var ref = e.missingSchema; - if (added(ref)) throw new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved'); +var queue = []; +// Once a flush has been requested, no further calls to `requestFlush` are +// necessary until the next `flush` completes. +var flushing = false; +// The position of the next task to execute in the task queue. This is +// preserved between calls to `flush` so that it can be resumed if +// a task throws an exception. +var index = 0; +// If a task schedules additional tasks recursively, the task queue can grow +// unbounded. To prevent memory excaustion, the task queue will periodically +// truncate already-completed tasks. +var capacity = 1024; - var schemaPromise = self._loadingSchemas[ref]; - if (!schemaPromise) { - schemaPromise = self._loadingSchemas[ref] = self._opts.loadSchema(ref); - schemaPromise.then(removePromise, removePromise); - } +// The flush function processes all tasks that have been scheduled with +// `rawAsap` unless and until one of those tasks throws an exception. +// If a task throws an exception, `flush` ensures that its state will remain +// consistent and will resume where it left off when called again. +// However, `flush` does not make any arrangements to be called again if an +// exception is thrown. +function flush() { + while (index < queue.length) { + var currentIndex = index; + // Advance the index before calling the task. This ensures that we will + // begin flushing on the next task the task throws an error. + index = index + 1; + queue[currentIndex].call(); + // Prevent leaking memory for long chains of recursive calls to `asap`. + // If we call `asap` within tasks scheduled by `asap`, the queue will + // grow, but to avoid an O(n) walk for every task we execute, we don't + // shift tasks off the queue after they have been executed. + // Instead, we periodically shift 1024 tasks off the queue. + if (index > capacity) { + // Manually shift all values starting at the index back to the + // beginning of the queue. + for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { + queue[scan] = queue[scan + index]; + } + queue.length -= index; + index = 0; + } + } + queue.length = 0; + index = 0; + flushing = false; +} - return schemaPromise.then(function (sch) { - if (!added(ref)) { - return loadMetaSchemaOf(sch).then(function () { - if (!added(ref)) self.addSchema(sch, ref, undefined, meta); - }); +rawAsap.requestFlush = requestFlush; +function requestFlush() { + // Ensure flushing is not bound to any domain. + // It is not sufficient to exit the domain, because domains exist on a stack. + // To execute code outside of any domain, the following dance is necessary. + var parentDomain = process.domain; + if (parentDomain) { + if (!domain) { + // Lazy execute the domain module. + // Only employed if the user elects to use domains. + domain = __webpack_require__(965); } - }).then(function() { - return _compileAsync(schemaObj); - }); + domain.active = process.domain = null; + } - function removePromise() { - delete self._loadingSchemas[ref]; - } + // `setImmediate` is slower that `process.nextTick`, but `process.nextTick` + // cannot handle recursion. + // `requestFlush` will only be called recursively from `asap.js`, to resume + // flushing after an error is thrown into a domain. + // Conveniently, `setImmediate` was introduced in the same version + // `process.nextTick` started throwing recursion errors. + if (flushing && hasSetImmediate) { + setImmediate(flush); + } else { + process.nextTick(flush); + } - function added(ref) { - return self._refs[ref] || self._schemas[ref]; - } + if (parentDomain) { + domain.active = process.domain = parentDomain; } - } } /***/ }), -/* 477 */ +/* 482 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +// Copyright 2011 Mark Cavage All rights reserved. +var errors = __webpack_require__(203); +var types = __webpack_require__(204); -var util = __webpack_require__(106); +var Reader = __webpack_require__(483); +var Writer = __webpack_require__(484); -var DATE = /^\d\d\d\d-(\d\d)-(\d\d)$/; -var DAYS = [0,31,29,31,30,31,30,31,31,30,31,30,31]; -var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d:\d\d)?$/i; -var HOSTNAME = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*$/i; -var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; -var URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; -// uri-template: https://tools.ietf.org/html/rfc6570 -var URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; -// For the source: https://gist.github.com/dperini/729294 -// For test cases: https://mathiasbynens.be/demo/url-regex -// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983. -// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu; -var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i; -var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; -var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$|^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; -var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; +// --- Exports -module.exports = formats; +module.exports = { -function formats(mode) { - mode = mode == 'full' ? 'full' : 'fast'; - return util.copy(formats[mode]); -} + Reader: Reader, + Writer: Writer -formats.fast = { - // date: http://tools.ietf.org/html/rfc3339#section-5.6 - date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/, - // date-time: http://tools.ietf.org/html/rfc3339#section-5.6 - time: /^[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i, - 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s][0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i, - // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js - uri: /^(?:[a-z][a-z0-9+-.]*)(?::|\/)\/?[^\s]*$/i, - 'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/\/)?[^\s]*$/i, - 'uri-template': URITEMPLATE, - url: URL, - // email (sources from jsen validator): - // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363 - // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation') - email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i, - hostname: HOSTNAME, - // optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html - ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, - // optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses - ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex, - // uuid: http://tools.ietf.org/html/rfc4122 - uuid: UUID, - // JSON-pointer: https://tools.ietf.org/html/rfc6901 - // uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A - 'json-pointer': JSON_POINTER, - // relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00 - 'relative-json-pointer': RELATIVE_JSON_POINTER }; +for (var t in types) { + if (types.hasOwnProperty(t)) + module.exports[t] = types[t]; +} +for (var e in errors) { + if (errors.hasOwnProperty(e)) + module.exports[e] = errors[e]; +} -formats.full = { - date: date, - time: time, - 'date-time': date_time, - uri: uri, - 'uri-reference': URIREF, - 'uri-template': URITEMPLATE, - url: URL, - email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&''*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i, - hostname: hostname, - ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, - ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex, - uuid: UUID, - 'json-pointer': JSON_POINTER, - 'relative-json-pointer': RELATIVE_JSON_POINTER -}; +/***/ }), +/* 483 */ +/***/ (function(module, exports, __webpack_require__) { -function date(str) { - // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 - var matches = str.match(DATE); - if (!matches) return false; +// Copyright 2011 Mark Cavage All rights reserved. - var month = +matches[1]; - var day = +matches[2]; - return month >= 1 && month <= 12 && day >= 1 && day <= DAYS[month]; -} +var assert = __webpack_require__(28); +var Buffer = __webpack_require__(15).Buffer; +var ASN1 = __webpack_require__(204); +var errors = __webpack_require__(203); -function time(str, full) { - var matches = str.match(TIME); - if (!matches) return false; - var hour = matches[1]; - var minute = matches[2]; - var second = matches[3]; - var timeZone = matches[5]; - return hour <= 23 && minute <= 59 && second <= 59 && (!full || timeZone); -} +// --- Globals +var newInvalidAsn1Error = errors.newInvalidAsn1Error; -var DATE_TIME_SEPARATOR = /t|\s/i; -function date_time(str) { - // http://tools.ietf.org/html/rfc3339#section-5.6 - var dateTime = str.split(DATE_TIME_SEPARATOR); - return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true); -} -function hostname(str) { - // https://tools.ietf.org/html/rfc1034#section-3.5 - // https://tools.ietf.org/html/rfc1123#section-2 - return str.length <= 255 && HOSTNAME.test(str); -} +// --- API + +function Reader(data) { + if (!data || !Buffer.isBuffer(data)) + throw new TypeError('data must be a node Buffer'); + this._buf = data; + this._size = data.length; -var NOT_URI_FRAGMENT = /\/|:/; -function uri(str) { - // http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "." - return NOT_URI_FRAGMENT.test(str) && URI.test(str); + // These hold the "current" state + this._len = 0; + this._offset = 0; } +Object.defineProperty(Reader.prototype, 'length', { + enumerable: true, + get: function () { return (this._len); } +}); -var Z_ANCHOR = /[^\\]\\Z/; -function regex(str) { - if (Z_ANCHOR.test(str)) return false; - try { - new RegExp(str); - return true; - } catch(e) { - return false; - } -} +Object.defineProperty(Reader.prototype, 'offset', { + enumerable: true, + get: function () { return (this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'remain', { + get: function () { return (this._size - this._offset); } +}); +Object.defineProperty(Reader.prototype, 'buffer', { + get: function () { return (this._buf.slice(this._offset)); } +}); -/***/ }), -/* 478 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; +/** + * Reads a single byte and advances offset; you can pass in `true` to make this + * a "peek" operation (i.e., get the byte, but don't advance the offset). + * + * @param {Boolean} peek true means don't move offset. + * @return {Number} the next byte, null if not enough data. + */ +Reader.prototype.readByte = function (peek) { + if (this._size - this._offset < 1) + return null; + + var b = this._buf[this._offset] & 0xff; + + if (!peek) + this._offset += 1; + + return b; +}; -var resolve = __webpack_require__(203) - , util = __webpack_require__(106) - , errorClasses = __webpack_require__(202) - , stableStringify = __webpack_require__(389); +Reader.prototype.peek = function () { + return this.readByte(true); +}; -var validateGenerator = __webpack_require__(344); /** - * Functions below are used inside compiled validations function + * Reads a (potentially) variable length off the BER buffer. This call is + * not really meant to be called directly, as callers have to manipulate + * the internal buffer afterwards. + * + * As a result of this call, you can call `Reader.length`, until the + * next thing called that does a readLength. + * + * @return {Number} the amount of offset to advance the buffer. + * @throws {InvalidAsn1Error} on bad ASN.1 */ +Reader.prototype.readLength = function (offset) { + if (offset === undefined) + offset = this._offset; -var co = __webpack_require__(383); -var ucs2length = util.ucs2length; -var equal = __webpack_require__(204); + if (offset >= this._size) + return null; -// this error is thrown by async schemas to return validation errors via exception -var ValidationError = errorClasses.Validation; + var lenB = this._buf[offset++] & 0xff; + if (lenB === null) + return null; -module.exports = compile; + if ((lenB & 0x80) === 0x80) { + lenB &= 0x7f; + + if (lenB === 0) + throw newInvalidAsn1Error('Indefinite length not supported'); + + if (lenB > 4) + throw newInvalidAsn1Error('encoding too long'); + + if (this._size - offset < lenB) + return null; + + this._len = 0; + for (var i = 0; i < lenB; i++) + this._len = (this._len << 8) + (this._buf[offset++] & 0xff); + + } else { + // Wasn't a variable length + this._len = lenB; + } + + return offset; +}; /** - * Compiles schema to validation function - * @this Ajv - * @param {Object} schema schema object - * @param {Object} root object with information about the root schema for this schema - * @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution - * @param {String} baseId base ID for IDs in the schema - * @return {Function} validation function + * Parses the next sequence in this BER buffer. + * + * To get the length of the sequence, call `Reader.length`. + * + * @return {Number} the sequence's tag. */ -function compile(schema, root, localRefs, baseId) { - /* jshint validthis: true, evil: true */ - /* eslint no-shadow: 0 */ - var self = this - , opts = this._opts - , refVal = [ undefined ] - , refs = {} - , patterns = [] - , patternsHash = {} - , defaults = [] - , defaultsHash = {} - , customRules = []; +Reader.prototype.readSequence = function (tag) { + var seq = this.peek(); + if (seq === null) + return null; + if (tag !== undefined && tag !== seq) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + seq.toString(16)); - root = root || { schema: schema, refVal: refVal, refs: refs }; + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; - var c = checkCompiling.call(this, schema, root, baseId); - var compilation = this._compilations[c.index]; - if (c.compiling) return (compilation.callValidate = callValidate); + this._offset = o; + return seq; +}; - var formats = this._formats; - var RULES = this.RULES; - try { - var v = localCompile(schema, root, localRefs, baseId); - compilation.validate = v; - var cv = compilation.callValidate; - if (cv) { - cv.schema = v.schema; - cv.errors = null; - cv.refs = v.refs; - cv.refVal = v.refVal; - cv.root = v.root; - cv.$async = v.$async; - if (opts.sourceCode) cv.source = v.source; - } - return v; - } finally { - endCompiling.call(this, schema, root, baseId); - } +Reader.prototype.readInt = function () { + return this._readTag(ASN1.Integer); +}; - function callValidate() { - var validate = compilation.validate; - var result = validate.apply(null, arguments); - callValidate.errors = validate.errors; - return result; - } - function localCompile(_schema, _root, localRefs, baseId) { - var isRoot = !_root || (_root && _root.schema == _schema); - if (_root.schema != root.schema) - return compile.call(self, _schema, _root, localRefs, baseId); +Reader.prototype.readBoolean = function () { + return (this._readTag(ASN1.Boolean) === 0 ? false : true); +}; - var $async = _schema.$async === true; - var sourceCode = validateGenerator({ - isTop: true, - schema: _schema, - isRoot: isRoot, - baseId: baseId, - root: _root, - schemaPath: '', - errSchemaPath: '#', - errorPath: '""', - MissingRefError: errorClasses.MissingRef, - RULES: RULES, - validate: validateGenerator, - util: util, - resolve: resolve, - resolveRef: resolveRef, - usePattern: usePattern, - useDefault: useDefault, - useCustomRule: useCustomRule, - opts: opts, - formats: formats, - logger: self.logger, - self: self - }); +Reader.prototype.readEnumeration = function () { + return this._readTag(ASN1.Enumeration); +}; - sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode) - + vars(defaults, defaultCode) + vars(customRules, customRuleCode) - + sourceCode; - if (opts.processCode) sourceCode = opts.processCode(sourceCode); - // console.log('\n\n\n *** \n', JSON.stringify(sourceCode)); - var validate; - try { - var makeValidate = new Function( - 'self', - 'RULES', - 'formats', - 'root', - 'refVal', - 'defaults', - 'customRules', - 'co', - 'equal', - 'ucs2length', - 'ValidationError', - sourceCode - ); +Reader.prototype.readString = function (tag, retbuf) { + if (!tag) + tag = ASN1.OctetString; - validate = makeValidate( - self, - RULES, - formats, - root, - refVal, - defaults, - customRules, - co, - equal, - ucs2length, - ValidationError - ); + var b = this.peek(); + if (b === null) + return null; - refVal[0] = validate; - } catch(e) { - self.logger.error('Error compiling schema, function code:', sourceCode); - throw e; - } + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); - validate.schema = _schema; - validate.errors = null; - validate.refs = refs; - validate.refVal = refVal; - validate.root = isRoot ? validate : _root; - if ($async) validate.$async = true; - if (opts.sourceCode === true) { - validate.source = { - code: sourceCode, - patterns: patterns, - defaults: defaults - }; - } + var o = this.readLength(this._offset + 1); // stored in `length` - return validate; - } + if (o === null) + return null; - function resolveRef(baseId, ref, isRoot) { - ref = resolve.url(https://github.com/baseId,%20ref); - var refIndex = refs[ref]; - var _refVal, refCode; - if (refIndex !== undefined) { - _refVal = refVal[refIndex]; - refCode = 'refVal[' + refIndex + ']'; - return resolvedRef(_refVal, refCode); - } - if (!isRoot && root.refs) { - var rootRefId = root.refs[ref]; - if (rootRefId !== undefined) { - _refVal = root.refVal[rootRefId]; - refCode = addLocalRef(ref, _refVal); - return resolvedRef(_refVal, refCode); - } - } + if (this.length > this._size - o) + return null; - refCode = addLocalRef(ref); - var v = resolve.call(self, localCompile, root, ref); - if (v === undefined) { - var localSchema = localRefs && localRefs[ref]; - if (localSchema) { - v = resolve.inlineRef(localSchema, opts.inlineRefs) - ? localSchema - : compile.call(self, localSchema, root, localRefs, baseId); - } - } + this._offset = o; - if (v === undefined) { - removeLocalRef(ref); - } else { - replaceLocalRef(ref, v); - return resolvedRef(v, refCode); - } - } + if (this.length === 0) + return retbuf ? Buffer.alloc(0) : ''; - function addLocalRef(ref, v) { - var refId = refVal.length; - refVal[refId] = v; - refs[ref] = refId; - return 'refVal' + refId; - } + var str = this._buf.slice(this._offset, this._offset + this.length); + this._offset += this.length; - function removeLocalRef(ref) { - delete refs[ref]; - } + return retbuf ? str : str.toString('utf8'); +}; - function replaceLocalRef(ref, v) { - var refId = refs[ref]; - refVal[refId] = v; - } +Reader.prototype.readOID = function (tag) { + if (!tag) + tag = ASN1.OID; - function resolvedRef(refVal, code) { - return typeof refVal == 'object' || typeof refVal == 'boolean' - ? { code: code, schema: refVal, inline: true } - : { code: code, $async: refVal && refVal.$async }; - } + var b = this.readString(tag, true); + if (b === null) + return null; - function usePattern(regexStr) { - var index = patternsHash[regexStr]; - if (index === undefined) { - index = patternsHash[regexStr] = patterns.length; - patterns[index] = regexStr; - } - return 'pattern' + index; - } + var values = []; + var value = 0; - function useDefault(value) { - switch (typeof value) { - case 'boolean': - case 'number': - return '' + value; - case 'string': - return util.toQuotedString(value); - case 'object': - if (value === null) return 'null'; - var valueStr = stableStringify(value); - var index = defaultsHash[valueStr]; - if (index === undefined) { - index = defaultsHash[valueStr] = defaults.length; - defaults[index] = value; - } - return 'default' + index; + for (var i = 0; i < b.length; i++) { + var byte = b[i] & 0xff; + + value <<= 7; + value += byte & 0x7f; + if ((byte & 0x80) === 0) { + values.push(value); + value = 0; } } - function useCustomRule(rule, schema, parentSchema, it) { - var validateSchema = rule.definition.validateSchema; - if (validateSchema && self._opts.validateSchema !== false) { - var valid = validateSchema(schema); - if (!valid) { - var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors); - if (self._opts.validateSchema == 'log') self.logger.error(message); - else throw new Error(message); - } - } + value = values.shift(); + values.unshift(value % 40); + values.unshift((value / 40) >> 0); - var compile = rule.definition.compile - , inline = rule.definition.inline - , macro = rule.definition.macro; + return values.join('.'); +}; - var validate; - if (compile) { - validate = compile.call(self, schema, parentSchema, it); - } else if (macro) { - validate = macro.call(self, schema, parentSchema, it); - if (opts.validateSchema !== false) self.validateSchema(validate, true); - } else if (inline) { - validate = inline.call(self, it, rule.keyword, schema, parentSchema); - } else { - validate = rule.definition.validate; - if (!validate) return; - } - if (validate === undefined) - throw new Error('custom keyword "' + rule.keyword + '"failed to compile'); +Reader.prototype._readTag = function (tag) { + assert.ok(tag !== undefined); - var index = customRules.length; - customRules[index] = validate; + var b = this.peek(); - return { - code: 'customRule' + index, - validate: validate - }; - } -} + if (b === null) + return null; + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); -/** - * Checks if the schema is currently compiled - * @this Ajv - * @param {Object} schema schema to compile - * @param {Object} root root object - * @param {String} baseId base schema ID - * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean) - */ -function checkCompiling(schema, root, baseId) { - /* jshint validthis: true */ - var index = compIndex.call(this, schema, root, baseId); - if (index >= 0) return { index: index, compiling: true }; - index = this._compilations.length; - this._compilations[index] = { - schema: schema, - root: root, - baseId: baseId - }; - return { index: index, compiling: false }; -} + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + if (this.length > 4) + throw newInvalidAsn1Error('Integer too long: ' + this.length); -/** - * Removes the schema from the currently compiled list - * @this Ajv - * @param {Object} schema schema to compile - * @param {Object} root root object - * @param {String} baseId base schema ID - */ -function endCompiling(schema, root, baseId) { - /* jshint validthis: true */ - var i = compIndex.call(this, schema, root, baseId); - if (i >= 0) this._compilations.splice(i, 1); -} + if (this.length > this._size - o) + return null; + this._offset = o; + var fb = this._buf[this._offset]; + var value = 0; -/** - * Index of schema compilation in the currently compiled list - * @this Ajv - * @param {Object} schema schema to compile - * @param {Object} root root object - * @param {String} baseId base schema ID - * @return {Integer} compilation index - */ -function compIndex(schema, root, baseId) { - /* jshint validthis: true */ - for (var i=0; i> 0; +}; -function defaultCode(i) { - return 'var default' + i + ' = defaults[' + i + '];'; -} +// --- Exported API -function refValCode(i, refVal) { - return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];'; -} +module.exports = Reader; -function customRuleCode(i) { - return 'var customRule' + i + ' = customRules[' + i + '];'; -} +/***/ }), +/* 484 */ +/***/ (function(module, exports, __webpack_require__) { +// Copyright 2011 Mark Cavage All rights reserved. -function vars(arr, statement) { - if (!arr.length) return ''; - var code = ''; - for (var i=0; i= 0xD800 && value <= 0xDBFF && pos < len) { - // high surrogate, and there is a next character - value = str.charCodeAt(pos); - if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate - } + // A list of offsets in the buffer where we need to insert + // sequence tag/len pairs. + this._seq = []; +} + +Object.defineProperty(Writer.prototype, 'buffer', { + get: function () { + if (this._seq.length) + throw newInvalidAsn1Error(this._seq.length + ' unended sequence(s)'); + + return (this._buf.slice(0, this._offset)); } - return length; +}); + +Writer.prototype.writeByte = function (b) { + if (typeof (b) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(1); + this._buf[this._offset++] = b; }; -/***/ }), -/* 481 */ -/***/ (function(module, exports, __webpack_require__) { +Writer.prototype.writeInt = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Integer; -"use strict"; + var sz = 4; -module.exports = function generate_allOf(it, $keyword, $ruleType) { - var out = ' '; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - var $currentBaseId = $it.baseId, - $allSchemasEmpty = true; - var arr1 = $schema; - if (arr1) { - var $sch, $i = -1, - l1 = arr1.length - 1; - while ($i < l1) { - $sch = arr1[$i += 1]; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - $allSchemasEmpty = false; - $it.schema = $sch; - $it.schemaPath = $schemaPath + '[' + $i + ']'; - $it.errSchemaPath = $errSchemaPath + '/' + $i; - out += ' ' + (it.validate($it)) + ' '; - $it.baseId = $currentBaseId; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - } - } - if ($breakOnError) { - if ($allSchemasEmpty) { - out += ' if (true) { '; - } else { - out += ' ' + ($closingBraces.slice(0, -1)) + ' '; - } + while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && + (sz > 1)) { + sz--; + i <<= 8; } - out = it.util.cleanUpCode(out); - return out; -} - -/***/ }), -/* 482 */ -/***/ (function(module, exports, __webpack_require__) { + if (sz > 4) + throw newInvalidAsn1Error('BER ints cannot be > 0xffffffff'); -"use strict"; + this._ensure(2 + sz); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = sz; -module.exports = function generate_anyOf(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - var $noEmptySchema = $schema.every(function($sch) { - return it.util.schemaHasRules($sch, it.RULES.all); - }); - if ($noEmptySchema) { - var $currentBaseId = $it.baseId; - out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; '; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - var arr1 = $schema; - if (arr1) { - var $sch, $i = -1, - l1 = arr1.length - 1; - while ($i < l1) { - $sch = arr1[$i += 1]; - $it.schema = $sch; - $it.schemaPath = $schemaPath + '[' + $i + ']'; - $it.errSchemaPath = $errSchemaPath + '/' + $i; - out += ' ' + (it.validate($it)) + ' '; - $it.baseId = $currentBaseId; - out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { '; - $closingBraces += '}'; - } - } - it.compositeRule = $it.compositeRule = $wasComposite; - out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should match some schema in anyOf\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError(vErrors); '; - } else { - out += ' validate.errors = vErrors; return false; '; - } - } - out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; - if (it.opts.allErrors) { - out += ' } '; - } - out = it.util.cleanUpCode(out); - } else { - if ($breakOnError) { - out += ' if (true) { '; - } + while (sz-- > 0) { + this._buf[this._offset++] = ((i & 0xff000000) >>> 24); + i <<= 8; } - return out; -} +}; -/***/ }), -/* 483 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; +Writer.prototype.writeNull = function () { + this.writeByte(ASN1.Null); + this.writeByte(0x00); +}; -module.exports = function generate_const(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - if (!$isData) { - out += ' var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + ';'; - } - out += 'var ' + ($valid) + ' = equal(' + ($data) + ', schema' + ($lvl) + '); if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('const') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should be equal to constant\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' }'; - if ($breakOnError) { - out += ' else { '; + +Writer.prototype.writeEnumeration = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Enumeration; + + return this.writeInt(i, tag); +}; + + +Writer.prototype.writeBoolean = function (b, tag) { + if (typeof (b) !== 'boolean') + throw new TypeError('argument must be a Boolean'); + if (typeof (tag) !== 'number') + tag = ASN1.Boolean; + + this._ensure(3); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = 0x01; + this._buf[this._offset++] = b ? 0xff : 0x00; +}; + + +Writer.prototype.writeString = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string (was: ' + typeof (s) + ')'); + if (typeof (tag) !== 'number') + tag = ASN1.OctetString; + + var len = Buffer.byteLength(s); + this.writeByte(tag); + this.writeLength(len); + if (len) { + this._ensure(len); + this._buf.write(s, this._offset); + this._offset += len; } - return out; -} +}; -/***/ }), -/* 484 */ -/***/ (function(module, exports, __webpack_require__) { +Writer.prototype.writeBuffer = function (buf, tag) { + if (typeof (tag) !== 'number') + throw new TypeError('tag must be a number'); + if (!Buffer.isBuffer(buf)) + throw new TypeError('argument must be a buffer'); -"use strict"; + this.writeByte(tag); + this.writeLength(buf.length); + this._ensure(buf.length); + buf.copy(this._buf, this._offset, 0, buf.length); + this._offset += buf.length; +}; -module.exports = function generate_contains(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - var $idx = 'i' + $lvl, - $dataNxt = $it.dataLevel = it.dataLevel + 1, - $nextData = 'data' + $dataNxt, - $currentBaseId = it.baseId, - $nonEmptySchema = it.util.schemaHasRules($schema, it.RULES.all); - out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; - if ($nonEmptySchema) { - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - $it.schema = $schema; - $it.schemaPath = $schemaPath; - $it.errSchemaPath = $errSchemaPath; - out += ' var ' + ($nextValid) + ' = false; for (var ' + ($idx) + ' = 0; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; - $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); - var $passData = $data + '[' + $idx + ']'; - $it.dataPathArr[$dataNxt] = $idx; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; + +Writer.prototype.writeStringArray = function (strings) { + if ((!strings instanceof Array)) + throw new TypeError('argument must be an Array[String]'); + + var self = this; + strings.forEach(function (s) { + self.writeString(s); + }); +}; + +// This is really to solve DER cases, but whatever for now +Writer.prototype.writeOID = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string'); + if (typeof (tag) !== 'number') + tag = ASN1.OID; + + if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) + throw new Error('argument is not a valid OID string'); + + function encodeOctet(bytes, octet) { + if (octet < 128) { + bytes.push(octet); + } else if (octet < 16384) { + bytes.push((octet >>> 7) | 0x80); + bytes.push(octet & 0x7F); + } else if (octet < 2097152) { + bytes.push((octet >>> 14) | 0x80); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else if (octet < 268435456) { + bytes.push((octet >>> 21) | 0x80); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; + bytes.push(((octet >>> 28) | 0x80) & 0xFF); + bytes.push(((octet >>> 21) | 0x80) & 0xFF); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); } - out += ' if (' + ($nextValid) + ') break; } '; - it.compositeRule = $it.compositeRule = $wasComposite; - out += ' ' + ($closingBraces) + ' if (!' + ($nextValid) + ') {'; - } else { - out += ' if (' + ($data) + '.length == 0) {'; } - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('contains') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should contain a valid item\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; + + var tmp = s.split('.'); + var bytes = []; + bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); + tmp.slice(2).forEach(function (b) { + encodeOctet(bytes, parseInt(b, 10)); + }); + + var self = this; + this._ensure(2 + bytes.length); + this.writeByte(tag); + this.writeLength(bytes.length); + bytes.forEach(function (b) { + self.writeByte(b); + }); +}; + + +Writer.prototype.writeLength = function (len) { + if (typeof (len) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(4); + + if (len <= 0x7f) { + this._buf[this._offset++] = len; + } else if (len <= 0xff) { + this._buf[this._offset++] = 0x81; + this._buf[this._offset++] = len; + } else if (len <= 0xffff) { + this._buf[this._offset++] = 0x82; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else if (len <= 0xffffff) { + this._buf[this._offset++] = 0x83; + this._buf[this._offset++] = len >> 16; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; } else { - out += ' {} '; + throw newInvalidAsn1Error('Length too long (> 4 bytes)'); } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } +}; + +Writer.prototype.startSequence = function (tag) { + if (typeof (tag) !== 'number') + tag = ASN1.Sequence | ASN1.Constructor; + + this.writeByte(tag); + this._seq.push(this._offset); + this._ensure(3); + this._offset += 3; +}; + + +Writer.prototype.endSequence = function () { + var seq = this._seq.pop(); + var start = seq + 3; + var len = this._offset - start; + + if (len <= 0x7f) { + this._shift(start, len, -2); + this._buf[seq] = len; + } else if (len <= 0xff) { + this._shift(start, len, -1); + this._buf[seq] = 0x81; + this._buf[seq + 1] = len; + } else if (len <= 0xffff) { + this._buf[seq] = 0x82; + this._buf[seq + 1] = len >> 8; + this._buf[seq + 2] = len; + } else if (len <= 0xffffff) { + this._shift(start, len, 1); + this._buf[seq] = 0x83; + this._buf[seq + 1] = len >> 16; + this._buf[seq + 2] = len >> 8; + this._buf[seq + 3] = len; } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else { '; - if ($nonEmptySchema) { - out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; + throw newInvalidAsn1Error('Sequence too long'); } - if (it.opts.allErrors) { - out += ' } '; +}; + + +Writer.prototype._shift = function (start, len, shift) { + assert.ok(start !== undefined); + assert.ok(len !== undefined); + assert.ok(shift); + + this._buf.copy(this._buf, start + shift, start, start + len); + this._offset += shift; +}; + +Writer.prototype._ensure = function (len) { + assert.ok(len); + + if (this._size - this._offset < len) { + var sz = this._size * this._options.growthFactor; + if (sz - this._offset < len) + sz += len; + + var buf = Buffer.alloc(sz); + + this._buf.copy(buf, 0, 0, this._offset); + this._buf = buf; + this._size = sz; } - out = it.util.cleanUpCode(out); - return out; -} +}; + + + +// --- Exported API + +module.exports = Writer; /***/ }), /* 485 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -module.exports = function generate_custom(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $errorKeyword; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - var $rule = this, - $definition = 'definition' + $lvl, - $rDef = $rule.definition, - $closingBraces = ''; - var $compile, $inline, $macro, $ruleValidate, $validateCode; - if ($isData && $rDef.$data) { - $validateCode = 'keywordValidate' + $lvl; - var $validateSchema = $rDef.validateSchema; - out += ' var ' + ($definition) + ' = RULES.custom[\'' + ($keyword) + '\'].definition; var ' + ($validateCode) + ' = ' + ($definition) + '.validate;'; - } else { - $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it); - if (!$ruleValidate) return; - $schemaValue = 'validate.schema' + $schemaPath; - $validateCode = $ruleValidate.code; - $compile = $rDef.compile; - $inline = $rDef.inline; - $macro = $rDef.macro; - } - var $ruleErrs = $validateCode + '.errors', - $i = 'i' + $lvl, - $ruleErr = 'ruleErr' + $lvl, - $asyncKeyword = $rDef.async; - if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema'); - if (!($inline || $macro)) { - out += '' + ($ruleErrs) + ' = null;'; - } - out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; - if ($isData && $rDef.$data) { - $closingBraces += '}'; - out += ' if (' + ($schemaValue) + ' === undefined) { ' + ($valid) + ' = true; } else { '; - if ($validateSchema) { - $closingBraces += '}'; - out += ' ' + ($valid) + ' = ' + ($definition) + '.validateSchema(' + ($schemaValue) + '); if (' + ($valid) + ') { '; - } - } - if ($inline) { - if ($rDef.statements) { - out += ' ' + ($ruleValidate.validate) + ' '; - } else { - out += ' ' + ($valid) + ' = ' + ($ruleValidate.validate) + '; '; - } - } else if ($macro) { - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - $it.schema = $ruleValidate.validate; - $it.schemaPath = ''; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - var $code = it.validate($it).replace(/validate\.schema/g, $validateCode); - it.compositeRule = $it.compositeRule = $wasComposite; - out += ' ' + ($code); - } else { - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; - out += ' ' + ($validateCode) + '.call( '; - if (it.opts.passContext) { - out += 'this'; - } else { - out += 'self'; - } - if ($compile || $rDef.schema === false) { - out += ' , ' + ($data) + ' '; - } else { - out += ' , ' + ($schemaValue) + ' , ' + ($data) + ' , validate.schema' + (it.schemaPath) + ' '; - } - out += ' , (dataPath || \'\')'; - if (it.errorPath != '""') { - out += ' + ' + (it.errorPath); - } - var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', - $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; - out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ' , rootData ) '; - var def_callRuleValidate = out; - out = $$outStack.pop(); - if ($rDef.errors === false) { - out += ' ' + ($valid) + ' = '; - if ($asyncKeyword) { - out += '' + (it.yieldAwait); - } - out += '' + (def_callRuleValidate) + '; '; - } else { - if ($asyncKeyword) { - $ruleErrs = 'customErrors' + $lvl; - out += ' var ' + ($ruleErrs) + ' = null; try { ' + ($valid) + ' = ' + (it.yieldAwait) + (def_callRuleValidate) + '; } catch (e) { ' + ($valid) + ' = false; if (e instanceof ValidationError) ' + ($ruleErrs) + ' = e.errors; else throw e; } '; - } else { - out += ' ' + ($ruleErrs) + ' = null; ' + ($valid) + ' = ' + (def_callRuleValidate) + '; '; - } - } - } - if ($rDef.modifying) { - out += ' if (' + ($parentData) + ') ' + ($data) + ' = ' + ($parentData) + '[' + ($parentDataProperty) + '];'; - } - out += '' + ($closingBraces); - if ($rDef.valid) { - if ($breakOnError) { - out += ' if (true) { '; - } - } else { - out += ' if ( '; - if ($rDef.valid === undefined) { - out += ' !'; - if ($macro) { - out += '' + ($nextValid); - } else { - out += '' + ($valid); - } - } else { - out += ' ' + (!$rDef.valid) + ' '; - } - out += ') { '; - $errorKeyword = $rule.keyword; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - var def_customError = out; - out = $$outStack.pop(); - if ($inline) { - if ($rDef.errors) { - if ($rDef.errors != 'full') { - out += ' for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '= 0) { - if ($breakOnError) { - out += ' if (true) { '; - } - return out; - } else { - throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); - } - } - var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate; - var $formatType = $isObject && $format.type || 'string'; - if ($isObject) { - var $async = $format.async === true; - $format = $format.validate; - } - if ($formatType != $ruleType) { - if ($breakOnError) { - out += ' if (true) { '; - } - return out; - } - if ($async) { - if (!it.async) throw new Error('async format in sync schema'); - var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate'; - out += ' if (!(' + (it.yieldAwait) + ' ' + ($formatRef) + '(' + ($data) + '))) { '; - } else { - out += ' if (! '; - var $formatRef = 'formats' + it.util.getProperty($schema); - if ($isObject) $formatRef += '.validate'; - if (typeof $format == 'function') { - out += ' ' + ($formatRef) + '(' + ($data) + ') '; - } else { - out += ' ' + ($formatRef) + '.test(' + ($data) + ') '; - } - out += ') { '; - } - } - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: '; - if ($isData) { - out += '' + ($schemaValue); - } else { - out += '' + (it.util.toQuotedString($schema)); - } - out += ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should match format "'; - if ($isData) { - out += '\' + ' + ($schemaValue) + ' + \''; - } else { - out += '' + (it.util.escapeQuotes($schema)); - } - out += '"\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + (it.util.toQuotedString($schema)); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - if ($breakOnError) { - out += ' else { '; - } - return out; +// Public API +module.exports = serial; + +/** + * Runs iterator over provided array elements in series + * + * @param {array|object} list - array or object (named list) to iterate over + * @param {function} iterator - iterator to run + * @param {function} callback - invoked when all elements processed + * @returns {function} - jobs terminator + */ +function serial(list, iterator, callback) +{ + return serialOrdered(list, iterator, null, callback); } @@ -91579,954 +90891,794 @@ module.exports = function generate_format(it, $keyword, $ruleType) { /* 489 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -module.exports = function generate_items(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - var $idx = 'i' + $lvl, - $dataNxt = $it.dataLevel = it.dataLevel + 1, - $nextData = 'data' + $dataNxt, - $currentBaseId = it.baseId; - out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';'; - if (Array.isArray($schema)) { - var $additionalItems = it.schema.additionalItems; - if ($additionalItems === false) { - out += ' ' + ($valid) + ' = ' + ($data) + '.length <= ' + ($schema.length) + '; '; - var $currErrSchemaPath = $errSchemaPath; - $errSchemaPath = it.errSchemaPath + '/additionalItems'; - out += ' if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('additionalItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schema.length) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have more than ' + ($schema.length) + ' items\' '; - } - if (it.opts.verbose) { - out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - $errSchemaPath = $currErrSchemaPath; - if ($breakOnError) { - $closingBraces += '}'; - out += ' else { '; - } - } - var arr1 = $schema; - if (arr1) { - var $sch, $i = -1, - l1 = arr1.length - 1; - while ($i < l1) { - $sch = arr1[$i += 1]; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($i) + ') { '; - var $passData = $data + '[' + $i + ']'; - $it.schema = $sch; - $it.schemaPath = $schemaPath + '[' + $i + ']'; - $it.errSchemaPath = $errSchemaPath + '/' + $i; - $it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true); - $it.dataPathArr[$dataNxt] = $i; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - out += ' } '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - } - } - if (typeof $additionalItems == 'object' && it.util.schemaHasRules($additionalItems, it.RULES.all)) { - $it.schema = $additionalItems; - $it.schemaPath = it.schemaPath + '.additionalItems'; - $it.errSchemaPath = it.errSchemaPath + '/additionalItems'; - out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($schema.length) + ') { for (var ' + ($idx) + ' = ' + ($schema.length) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; - $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); - var $passData = $data + '[' + $idx + ']'; - $it.dataPathArr[$dataNxt] = $idx; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - if ($breakOnError) { - out += ' if (!' + ($nextValid) + ') break; '; - } - out += ' } } '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - } else if (it.util.schemaHasRules($schema, it.RULES.all)) { - $it.schema = $schema; - $it.schemaPath = $schemaPath; - $it.errSchemaPath = $errSchemaPath; - out += ' for (var ' + ($idx) + ' = ' + (0) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { '; - $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); - var $passData = $data + '[' + $idx + ']'; - $it.dataPathArr[$dataNxt] = $idx; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - if ($breakOnError) { - out += ' if (!' + ($nextValid) + ') break; '; - } - out += ' }'; - } - if ($breakOnError) { - out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; +/*! + * Copyright 2010 LearnBoost + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Module dependencies. + */ + +var crypto = __webpack_require__(11) + , parse = __webpack_require__(24).parse + ; + +/** + * Valid keys. + */ + +var keys = + [ 'acl' + , 'location' + , 'logging' + , 'notification' + , 'partNumber' + , 'policy' + , 'requestPayment' + , 'torrent' + , 'uploadId' + , 'uploads' + , 'versionId' + , 'versioning' + , 'versions' + , 'website' + ] + +/** + * Return an "Authorization" header value with the given `options` + * in the form of "AWS :" + * + * @param {Object} options + * @return {String} + * @api private + */ + +function authorization (options) { + return 'AWS ' + options.key + ':' + sign(options) +} + +module.exports = authorization +module.exports.authorization = authorization + +/** + * Simple HMAC-SHA1 Wrapper + * + * @param {Object} options + * @return {String} + * @api private + */ + +function hmacSha1 (options) { + return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64') +} + +module.exports.hmacSha1 = hmacSha1 + +/** + * Create a base64 sha1 HMAC for `options`. + * + * @param {Object} options + * @return {String} + * @api private + */ + +function sign (options) { + options.message = stringToSign(options) + return hmacSha1(options) +} +module.exports.sign = sign + +/** + * Create a base64 sha1 HMAC for `options`. + * + * Specifically to be used with S3 presigned URLs + * + * @param {Object} options + * @return {String} + * @api private + */ + +function signQuery (options) { + options.message = queryStringToSign(options) + return hmacSha1(options) +} +module.exports.signQuery= signQuery + +/** + * Return a string for sign() with the given `options`. + * + * Spec: + * + * \n + * \n + * \n + * \n + * [headers\n] + * + * + * @param {Object} options + * @return {String} + * @api private + */ + +function stringToSign (options) { + var headers = options.amazonHeaders || '' + if (headers) headers += '\n' + var r = + [ options.verb + , options.md5 + , options.contentType + , options.date ? options.date.toUTCString() : '' + , headers + options.resource + ] + return r.join('\n') +} +module.exports.stringToSign = stringToSign + +/** + * Return a string for sign() with the given `options`, but is meant exclusively + * for S3 presigned URLs + * + * Spec: + * + * \n + * + * + * @param {Object} options + * @return {String} + * @api private + */ + +function queryStringToSign (options){ + return 'GET\n\n\n' + options.date + '\n' + options.resource +} +module.exports.queryStringToSign = queryStringToSign + +/** + * Perform the following: + * + * - ignore non-amazon headers + * - lowercase fields + * - sort lexicographically + * - trim whitespace between ":" + * - join with newline + * + * @param {Object} headers + * @return {String} + * @api private + */ + +function canonicalizeHeaders (headers) { + var buf = [] + , fields = Object.keys(headers) + ; + for (var i = 0, len = fields.length; i < len; ++i) { + var field = fields[i] + , val = headers[field] + , field = field.toLowerCase() + ; + if (0 !== field.indexOf('x-amz')) continue + buf.push(field + ':' + val) } - out = it.util.cleanUpCode(out); - return out; + return buf.sort().join('\n') +} +module.exports.canonicalizeHeaders = canonicalizeHeaders + +/** + * Perform the following: + * + * - ignore non sub-resources + * - sort lexicographically + * + * @param {String} resource + * @return {String} + * @api private + */ + +function canonicalizeResource (resource) { + var url = parse(resource, true) + , path = url.pathname + , buf = [] + ; + + Object.keys(url.query).forEach(function(key){ + if (!~keys.indexOf(key)) return + var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]) + buf.push(key + val) + }) + + return path + (buf.length ? '?' + buf.sort().join('&') : '') } +module.exports.canonicalizeResource = canonicalizeResource /***/ }), /* 490 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +var aws4 = exports, + url = __webpack_require__(24), + querystring = __webpack_require__(197), + crypto = __webpack_require__(11), + lru = __webpack_require__(491), + credentialsCache = lru(1000) -module.exports = function generate_multipleOf(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - out += 'var division' + ($lvl) + ';if ('; - if ($isData) { - out += ' ' + ($schemaValue) + ' !== undefined && ( typeof ' + ($schemaValue) + ' != \'number\' || '; +// http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html + +function hmac(key, string, encoding) { + return crypto.createHmac('sha256', key).update(string, 'utf8').digest(encoding) +} + +function hash(string, encoding) { + return crypto.createHash('sha256').update(string, 'utf8').digest(encoding) +} + +// This function assumes the string has already been percent encoded +function encodeRfc3986(urlEncodedString) { + return urlEncodedString.replace(/[!'()*]/g, function(c) { + return '%' + c.charCodeAt(0).toString(16).toUpperCase() + }) +} + +// request: { path | body, [host], [method], [headers], [service], [region] } +// credentials: { accessKeyId, secretAccessKey, [sessionToken] } +function RequestSigner(request, credentials) { + + if (typeof request === 'string') request = url.parse(request) + + var headers = request.headers = (request.headers || {}), + hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host) + + this.request = request + this.credentials = credentials || this.defaultCredentials() + + this.service = request.service || hostParts[0] || '' + this.region = request.region || hostParts[1] || 'us-east-1' + + // SES uses a different domain from the service name + if (this.service === 'email') this.service = 'ses' + + if (!request.method && request.body) + request.method = 'POST' + + if (!headers.Host && !headers.host) { + headers.Host = request.hostname || request.host || this.createHost() + + // If a port is specified explicitly, use it as is + if (request.port) + headers.Host += ':' + request.port } - out += ' (division' + ($lvl) + ' = ' + ($data) + ' / ' + ($schemaValue) + ', '; - if (it.opts.multipleOfPrecision) { - out += ' Math.abs(Math.round(division' + ($lvl) + ') - division' + ($lvl) + ') > 1e-' + (it.opts.multipleOfPrecision) + ' '; + if (!request.hostname && !request.host) + request.hostname = headers.Host || headers.host + + this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT' +} + +RequestSigner.prototype.matchHost = function(host) { + var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com$/) + var hostParts = (match || []).slice(1, 3) + + // ES's hostParts are sometimes the other way round, if the value that is expected + // to be region equals ‘es’ switch them back + // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com + if (hostParts[1] === 'es') + hostParts = hostParts.reverse() + + return hostParts +} + +// http://docs.aws.amazon.com/general/latest/gr/rande.html +RequestSigner.prototype.isSingleRegion = function() { + // Special case for S3 and SimpleDB in us-east-1 + if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true + + return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'] + .indexOf(this.service) >= 0 +} + +RequestSigner.prototype.createHost = function() { + var region = this.isSingleRegion() ? '' : + (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region, + service = this.service === 'ses' ? 'email' : this.service + return service + region + '.amazonaws.com' +} + +RequestSigner.prototype.prepareRequest = function() { + this.parsePath() + + var request = this.request, headers = request.headers, query + + if (request.signQuery) { + + this.parsedPath.query = query = this.parsedPath.query || {} + + if (this.credentials.sessionToken) + query['X-Amz-Security-Token'] = this.credentials.sessionToken + + if (this.service === 's3' && !query['X-Amz-Expires']) + query['X-Amz-Expires'] = 86400 + + if (query['X-Amz-Date']) + this.datetime = query['X-Amz-Date'] + else + query['X-Amz-Date'] = this.getDateTime() + + query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256' + query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString() + query['X-Amz-SignedHeaders'] = this.signedHeaders() + } else { - out += ' division' + ($lvl) + ' !== parseInt(division' + ($lvl) + ') '; - } - out += ' ) '; - if ($isData) { - out += ' ) '; - } - out += ' ) { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('multipleOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { multipleOf: ' + ($schemaValue) + ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should be multiple of '; - if ($isData) { - out += '\' + ' + ($schemaValue); - } else { - out += '' + ($schemaValue) + '\''; - } - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + + if (!request.doNotModifyHeaders && !this.isCodeCommitGit) { + if (request.body && !headers['Content-Type'] && !headers['content-type']) + headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8' + + if (request.body && !headers['Content-Length'] && !headers['content-length']) + headers['Content-Length'] = Buffer.byteLength(request.body) + + if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token']) + headers['X-Amz-Security-Token'] = this.credentials.sessionToken + + if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256']) + headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex') + + if (headers['X-Amz-Date'] || headers['x-amz-date']) + this.datetime = headers['X-Amz-Date'] || headers['x-amz-date'] + else + headers['X-Amz-Date'] = this.getDateTime() } - out += ' } '; - } else { - out += ' {} '; + + delete headers.Authorization + delete headers.authorization } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } +} + +RequestSigner.prototype.sign = function() { + if (!this.parsedPath) this.prepareRequest() + + if (this.request.signQuery) { + this.parsedPath.query['X-Amz-Signature'] = this.signature() } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; + this.request.headers.Authorization = this.authHeader() } - out += '} '; - if ($breakOnError) { - out += ' else { '; + + this.request.path = this.formatPath() + + return this.request +} + +RequestSigner.prototype.getDateTime = function() { + if (!this.datetime) { + var headers = this.request.headers, + date = new Date(headers.Date || headers.date || new Date) + + this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '') + + // Remove the trailing 'Z' on the timestamp string for CodeCommit git access + if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1) } - return out; + return this.datetime } +RequestSigner.prototype.getDate = function() { + return this.getDateTime().substr(0, 8) +} -/***/ }), -/* 491 */ -/***/ (function(module, exports, __webpack_require__) { +RequestSigner.prototype.authHeader = function() { + return [ + 'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), + 'SignedHeaders=' + this.signedHeaders(), + 'Signature=' + this.signature(), + ].join(', ') +} -"use strict"; +RequestSigner.prototype.signature = function() { + var date = this.getDate(), + cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(), + kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey) + if (!kCredentials) { + kDate = hmac('AWS4' + this.credentials.secretAccessKey, date) + kRegion = hmac(kDate, this.region) + kService = hmac(kRegion, this.service) + kCredentials = hmac(kService, 'aws4_request') + credentialsCache.set(cacheKey, kCredentials) + } + return hmac(kCredentials, this.stringToSign(), 'hex') +} -module.exports = function generate_not(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - $it.level++; - var $nextValid = 'valid' + $it.level; - if (it.util.schemaHasRules($schema, it.RULES.all)) { - $it.schema = $schema; - $it.schemaPath = $schemaPath; - $it.errSchemaPath = $errSchemaPath; - out += ' var ' + ($errs) + ' = errors; '; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - $it.createErrors = false; - var $allErrorsOption; - if ($it.opts.allErrors) { - $allErrorsOption = $it.opts.allErrors; - $it.opts.allErrors = false; - } - out += ' ' + (it.validate($it)) + ' '; - $it.createErrors = true; - if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption; - it.compositeRule = $it.compositeRule = $wasComposite; - out += ' if (' + ($nextValid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT be valid\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } '; - if (it.opts.allErrors) { - out += ' } '; - } +RequestSigner.prototype.stringToSign = function() { + return [ + 'AWS4-HMAC-SHA256', + this.getDateTime(), + this.credentialString(), + hash(this.canonicalString(), 'hex'), + ].join('\n') +} + +RequestSigner.prototype.canonicalString = function() { + if (!this.parsedPath) this.prepareRequest() + + var pathStr = this.parsedPath.path, + query = this.parsedPath.query, + headers = this.request.headers, + queryStr = '', + normalizePath = this.service !== 's3', + decodePath = this.service === 's3' || this.request.doNotEncodePath, + decodeSlashesInPath = this.service === 's3', + firstValOnly = this.service === 's3', + bodyHash + + if (this.service === 's3' && this.request.signQuery) { + bodyHash = 'UNSIGNED-PAYLOAD' + } else if (this.isCodeCommitGit) { + bodyHash = '' } else { - out += ' var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT be valid\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; + bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] || + hash(this.request.body || '', 'hex') + } + + if (query) { + queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function(obj, key) { + if (!key) return obj + obj[key] = !Array.isArray(query[key]) ? query[key] : + (firstValOnly ? query[key][0] : query[key].slice().sort()) + return obj + }, {}))) + } + if (pathStr !== '/') { + if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/') + pathStr = pathStr.split('/').reduce(function(path, piece) { + if (normalizePath && piece === '..') { + path.pop() + } else if (!normalizePath || piece !== '.') { + if (decodePath) piece = decodeURIComponent(piece) + path.push(encodeRfc3986(encodeURIComponent(piece))) } - out += ' } '; - } else { - out += ' {} '; - } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - if ($breakOnError) { - out += ' if (false) { '; - } + return path + }, []).join('/') + if (pathStr[0] !== '/') pathStr = '/' + pathStr + if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/') } - return out; + + return [ + this.request.method || 'GET', + pathStr, + queryStr, + this.canonicalHeaders() + '\n', + this.signedHeaders(), + bodyHash, + ].join('\n') } +RequestSigner.prototype.canonicalHeaders = function() { + var headers = this.request.headers + function trimAll(header) { + return header.toString().trim().replace(/\s+/g, ' ') + } + return Object.keys(headers) + .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 }) + .map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) }) + .join('\n') +} -/***/ }), -/* 492 */ -/***/ (function(module, exports, __webpack_require__) { +RequestSigner.prototype.signedHeaders = function() { + return Object.keys(this.request.headers) + .map(function(key) { return key.toLowerCase() }) + .sort() + .join(';') +} -"use strict"; +RequestSigner.prototype.credentialString = function() { + return [ + this.getDate(), + this.region, + this.service, + 'aws4_request', + ].join('/') +} -module.exports = function generate_oneOf(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - out += 'var ' + ($errs) + ' = errors;var prevValid' + ($lvl) + ' = false;var ' + ($valid) + ' = false;'; - var $currentBaseId = $it.baseId; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - var arr1 = $schema; - if (arr1) { - var $sch, $i = -1, - l1 = arr1.length - 1; - while ($i < l1) { - $sch = arr1[$i += 1]; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - $it.schema = $sch; - $it.schemaPath = $schemaPath + '[' + $i + ']'; - $it.errSchemaPath = $errSchemaPath + '/' + $i; - out += ' ' + (it.validate($it)) + ' '; - $it.baseId = $currentBaseId; - } else { - out += ' var ' + ($nextValid) + ' = true; '; - } - if ($i) { - out += ' if (' + ($nextValid) + ' && prevValid' + ($lvl) + ') ' + ($valid) + ' = false; else { '; - $closingBraces += '}'; - } - out += ' if (' + ($nextValid) + ') ' + ($valid) + ' = prevValid' + ($lvl) + ' = true;'; - } +RequestSigner.prototype.defaultCredentials = function() { + var env = process.env + return { + accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, + secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, + sessionToken: env.AWS_SESSION_TOKEN, } - it.compositeRule = $it.compositeRule = $wasComposite; - out += '' + ($closingBraces) + 'if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('oneOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; - if (it.opts.messages !== false) { - out += ' , message: \'should match exactly one schema in oneOf\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; +} + +RequestSigner.prototype.parsePath = function() { + var path = this.request.path || '/', + queryIx = path.indexOf('?'), + query = null + + if (queryIx >= 0) { + query = querystring.parse(path.slice(queryIx + 1)) + path = path.slice(0, queryIx) } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError(vErrors); '; - } else { - out += ' validate.errors = vErrors; return false; '; - } + + // S3 doesn't always encode characters > 127 correctly and + // all services don't encode characters > 255 correctly + // So if there are non-reserved chars (and it's not already all % encoded), just encode them all + if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) { + path = path.split('/').map(function(piece) { + return encodeURIComponent(decodeURIComponent(piece)) + }).join('/') } - out += '} else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; }'; - if (it.opts.allErrors) { - out += ' } '; + + this.parsedPath = { + path: path, + query: query, } - return out; +} + +RequestSigner.prototype.formatPath = function() { + var path = this.parsedPath.path, + query = this.parsedPath.query + + if (!query) return path + + // Services don't support empty query string keys + if (query[''] != null) delete query[''] + + return path + '?' + encodeRfc3986(querystring.stringify(query)) +} + +aws4.RequestSigner = RequestSigner + +aws4.sign = function(request, credentials) { + return new RequestSigner(request, credentials).sign() } /***/ }), -/* 493 */ -/***/ (function(module, exports, __webpack_require__) { +/* 491 */ +/***/ (function(module, exports) { -"use strict"; +module.exports = function(size) { + return new LruCache(size) +} -module.exports = function generate_pattern(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; +function LruCache(size) { + this.capacity = size | 0 + this.map = Object.create(null) + this.list = new DoublyLinkedList() +} + +LruCache.prototype.get = function(key) { + var node = this.map[key] + if (node == null) return undefined + this.used(node) + return node.val +} + +LruCache.prototype.set = function(key, val) { + var node = this.map[key] + if (node != null) { + node.val = val } else { - $schemaValue = $schema; + if (!this.capacity) this.prune() + if (!this.capacity) return false + node = new DoublyLinkedNode(key, val) + this.map[key] = node + this.capacity-- } - var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema); - out += 'if ( '; - if ($isData) { - out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || '; + this.used(node) + return true +} + +LruCache.prototype.used = function(node) { + this.list.moveToFront(node) +} + +LruCache.prototype.prune = function() { + var node = this.list.pop() + if (node != null) { + delete this.map[node.key] + this.capacity++ } - out += ' !' + ($regexp) + '.test(' + ($data) + ') ) { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('pattern') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { pattern: '; - if ($isData) { - out += '' + ($schemaValue); - } else { - out += '' + (it.util.toQuotedString($schema)); - } - out += ' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should match pattern "'; - if ($isData) { - out += '\' + ' + ($schemaValue) + ' + \''; - } else { - out += '' + (it.util.escapeQuotes($schema)); - } - out += '"\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + (it.util.toQuotedString($schema)); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; +} + + +function DoublyLinkedList() { + this.firstNode = null + this.lastNode = null +} + +DoublyLinkedList.prototype.moveToFront = function(node) { + if (this.firstNode == node) return + + this.remove(node) + + if (this.firstNode == null) { + this.firstNode = node + this.lastNode = node + node.prev = null + node.next = null } else { - out += ' {} '; + node.prev = null + node.next = this.firstNode + node.next.prev = node + this.firstNode = node } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; +} + +DoublyLinkedList.prototype.pop = function() { + var lastNode = this.lastNode + if (lastNode != null) { + this.remove(lastNode) } - out += '} '; - if ($breakOnError) { - out += ' else { '; + return lastNode +} + +DoublyLinkedList.prototype.remove = function(node) { + if (this.firstNode == node) { + this.firstNode = node.next + } else if (node.prev != null) { + node.prev.next = node.next + } + if (this.lastNode == node) { + this.lastNode = node.prev + } else if (node.next != null) { + node.next.prev = node.prev } - return out; +} + + +function DoublyLinkedNode(key, val) { + this.key = key + this.val = val + this.prev = null + this.next = null } /***/ }), -/* 494 */ +/* 492 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = function generate_properties(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - var $key = 'key' + $lvl, - $idx = 'idx' + $lvl, - $dataNxt = $it.dataLevel = it.dataLevel + 1, - $nextData = 'data' + $dataNxt, - $dataProperties = 'dataProperties' + $lvl; - var $schemaKeys = Object.keys($schema || {}), - $pProperties = it.schema.patternProperties || {}, - $pPropertyKeys = Object.keys($pProperties), - $aProperties = it.schema.additionalProperties, - $someProperties = $schemaKeys.length || $pPropertyKeys.length, - $noAdditional = $aProperties === false, - $additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length, - $removeAdditional = it.opts.removeAdditional, - $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional, - $ownProperties = it.opts.ownProperties, - $currentBaseId = it.baseId; - var $required = it.schema.required; - if ($required && !(it.opts.v5 && $required.$data) && $required.length < it.opts.loopRequired) var $requiredHash = it.util.toHash($required); - if (it.opts.patternGroups) { - var $pgProperties = it.schema.patternGroups || {}, - $pgPropertyKeys = Object.keys($pgProperties); - } - out += 'var ' + ($errs) + ' = errors;var ' + ($nextValid) + ' = true;'; - if ($ownProperties) { - out += ' var ' + ($dataProperties) + ' = undefined;'; - } - if ($checkAdditional) { - if ($ownProperties) { - out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; - } else { - out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; - } - if ($someProperties) { - out += ' var isAdditional' + ($lvl) + ' = !(false '; - if ($schemaKeys.length) { - if ($schemaKeys.length > 5) { - out += ' || validate.schema' + ($schemaPath) + '[' + ($key) + '] '; - } else { - var arr1 = $schemaKeys; - if (arr1) { - var $propertyKey, i1 = -1, - l1 = arr1.length - 1; - while (i1 < l1) { - $propertyKey = arr1[i1 += 1]; - out += ' || ' + ($key) + ' == ' + (it.util.toQuotedString($propertyKey)) + ' '; - } - } - } - } - if ($pPropertyKeys.length) { - var arr2 = $pPropertyKeys; - if (arr2) { - var $pProperty, $i = -1, - l2 = arr2.length - 1; - while ($i < l2) { - $pProperty = arr2[$i += 1]; - out += ' || ' + (it.usePattern($pProperty)) + '.test(' + ($key) + ') '; - } - } - } - if (it.opts.patternGroups && $pgPropertyKeys.length) { - var arr3 = $pgPropertyKeys; - if (arr3) { - var $pgProperty, $i = -1, - l3 = arr3.length - 1; - while ($i < l3) { - $pgProperty = arr3[$i += 1]; - out += ' || ' + (it.usePattern($pgProperty)) + '.test(' + ($key) + ') '; - } - } - } - out += ' ); if (isAdditional' + ($lvl) + ') { '; - } - if ($removeAdditional == 'all') { - out += ' delete ' + ($data) + '[' + ($key) + ']; '; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (message) { + return { + useless: true, + run() { + throw new (_errors || _load_errors()).MessageError(message); + }, + setFlags: () => {}, + hasWrapper: () => true + }; +}; + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); +} + +/***/ }), +/* 493 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.examples = exports.hasWrapper = exports.run = undefined; +exports.setFlags = setFlags; + +var _buildSubCommands2; + +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const notYetImplemented = () => Promise.reject(new Error('This command is not implemented yet.')); + +function setFlags(commander) { + commander.description('Has not been implemented yet'); +} + +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('access', { + public: notYetImplemented, + restricted: notYetImplemented, + grant: notYetImplemented, + revoke: notYetImplemented, + lsPackages: notYetImplemented, + lsCollaborators: notYetImplemented, + edit: notYetImplemented +}, ['WARNING: This command yet to be implemented.', 'public []', 'restricted []', 'grant []', 'revoke []', 'ls-packages [||]', 'ls-collaborators [ []]', 'edit []']); + +const run = _buildSubCommands.run, + hasWrapper = _buildSubCommands.hasWrapper, + examples = _buildSubCommands.examples; +exports.run = run; +exports.hasWrapper = hasWrapper; +exports.examples = examples; + +/***/ }), +/* 494 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const binFolder = path.join(config.cwd, config.registryFolders[0], '.bin'); + if (args.length === 0) { + reporter.log(binFolder, { force: true }); } else { - var $currentErrorPath = it.errorPath; - var $additionalProperty = '\' + ' + $key + ' + \''; - if (it.opts._errorDataPathProperty) { - it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); - } - if ($noAdditional) { - if ($removeAdditional) { - out += ' delete ' + ($data) + '[' + ($key) + ']; '; - } else { - out += ' ' + ($nextValid) + ' = false; '; - var $currErrSchemaPath = $errSchemaPath; - $errSchemaPath = it.errSchemaPath + '/additionalProperties'; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('additionalProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { additionalProperty: \'' + ($additionalProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have additional properties\' '; - } - if (it.opts.verbose) { - out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - $errSchemaPath = $currErrSchemaPath; - if ($breakOnError) { - out += ' break; '; - } - } - } else if ($additionalIsSchema) { - if ($removeAdditional == 'failing') { - out += ' var ' + ($errs) + ' = errors; '; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - $it.schema = $aProperties; - $it.schemaPath = it.schemaPath + '.additionalProperties'; - $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; - $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); - var $passData = $data + '[' + $key + ']'; - $it.dataPathArr[$dataNxt] = $key; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - out += ' if (!' + ($nextValid) + ') { errors = ' + ($errs) + '; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete ' + ($data) + '[' + ($key) + ']; } '; - it.compositeRule = $it.compositeRule = $wasComposite; - } else { - $it.schema = $aProperties; - $it.schemaPath = it.schemaPath + '.additionalProperties'; - $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; - $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); - var $passData = $data + '[' + $key + ']'; - $it.dataPathArr[$dataNxt] = $key; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - if ($breakOnError) { - out += ' if (!' + ($nextValid) + ') break; '; - } - } - } - it.errorPath = $currentErrorPath; - } - if ($someProperties) { - out += ' } '; - } - out += ' } '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - var $useDefaults = it.opts.useDefaults && !it.compositeRule; - if ($schemaKeys.length) { - var arr4 = $schemaKeys; - if (arr4) { - var $propertyKey, i4 = -1, - l4 = arr4.length - 1; - while (i4 < l4) { - $propertyKey = arr4[i4 += 1]; - var $sch = $schema[$propertyKey]; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - var $prop = it.util.getProperty($propertyKey), - $passData = $data + $prop, - $hasDefault = $useDefaults && $sch.default !== undefined; - $it.schema = $sch; - $it.schemaPath = $schemaPath + $prop; - $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey); - $it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers); - $it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey); - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - $code = it.util.varReplace($code, $nextData, $passData); - var $useData = $passData; - } else { - var $useData = $nextData; - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; '; - } - if ($hasDefault) { - out += ' ' + ($code) + ' '; - } else { - if ($requiredHash && $requiredHash[$propertyKey]) { - out += ' if ( ' + ($useData) + ' === undefined '; - if ($ownProperties) { - out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; - } - out += ') { ' + ($nextValid) + ' = false; '; - var $currentErrorPath = it.errorPath, - $currErrSchemaPath = $errSchemaPath, - $missingProperty = it.util.escapeQuotes($propertyKey); - if (it.opts._errorDataPathProperty) { - it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); - } - $errSchemaPath = it.errSchemaPath + '/required'; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - $errSchemaPath = $currErrSchemaPath; - it.errorPath = $currentErrorPath; - out += ' } else { '; - } else { - if ($breakOnError) { - out += ' if ( ' + ($useData) + ' === undefined '; - if ($ownProperties) { - out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; - } - out += ') { ' + ($nextValid) + ' = true; } else { '; - } else { - out += ' if (' + ($useData) + ' !== undefined '; - if ($ownProperties) { - out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; - } - out += ' ) { '; - } - } - out += ' ' + ($code) + ' } '; - } - } - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - } - } - if ($pPropertyKeys.length) { - var arr5 = $pPropertyKeys; - if (arr5) { - var $pProperty, i5 = -1, - l5 = arr5.length - 1; - while (i5 < l5) { - $pProperty = arr5[i5 += 1]; - var $sch = $pProperties[$pProperty]; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - $it.schema = $sch; - $it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty); - $it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty); - if ($ownProperties) { - out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; - } else { - out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; - } - out += ' if (' + (it.usePattern($pProperty)) + '.test(' + ($key) + ')) { '; - $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); - var $passData = $data + '[' + $key + ']'; - $it.dataPathArr[$dataNxt] = $key; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - if ($breakOnError) { - out += ' if (!' + ($nextValid) + ') break; '; - } - out += ' } '; - if ($breakOnError) { - out += ' else ' + ($nextValid) + ' = true; '; - } - out += ' } '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - } - } - } - } - if (it.opts.patternGroups && $pgPropertyKeys.length) { - var arr6 = $pgPropertyKeys; - if (arr6) { - var $pgProperty, i6 = -1, - l6 = arr6.length - 1; - while (i6 < l6) { - $pgProperty = arr6[i6 += 1]; - var $pgSchema = $pgProperties[$pgProperty], - $sch = $pgSchema.schema; - if (it.util.schemaHasRules($sch, it.RULES.all)) { - $it.schema = $sch; - $it.schemaPath = it.schemaPath + '.patternGroups' + it.util.getProperty($pgProperty) + '.schema'; - $it.errSchemaPath = it.errSchemaPath + '/patternGroups/' + it.util.escapeFragment($pgProperty) + '/schema'; - out += ' var pgPropCount' + ($lvl) + ' = 0; '; - if ($ownProperties) { - out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; - } else { - out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; - } - out += ' if (' + (it.usePattern($pgProperty)) + '.test(' + ($key) + ')) { pgPropCount' + ($lvl) + '++; '; - $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); - var $passData = $data + '[' + $key + ']'; - $it.dataPathArr[$dataNxt] = $key; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - if ($breakOnError) { - out += ' if (!' + ($nextValid) + ') break; '; - } - out += ' } '; - if ($breakOnError) { - out += ' else ' + ($nextValid) + ' = true; '; - } - out += ' } '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - $closingBraces += '}'; - } - var $pgMin = $pgSchema.minimum, - $pgMax = $pgSchema.maximum; - if ($pgMin !== undefined || $pgMax !== undefined) { - out += ' var ' + ($valid) + ' = true; '; - var $currErrSchemaPath = $errSchemaPath; - if ($pgMin !== undefined) { - var $limit = $pgMin, - $reason = 'minimum', - $moreOrLess = 'less'; - out += ' ' + ($valid) + ' = pgPropCount' + ($lvl) + ' >= ' + ($pgMin) + '; '; - $errSchemaPath = it.errSchemaPath + '/patternGroups/minimum'; - out += ' if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('patternGroups') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { reason: \'' + ($reason) + '\', limit: ' + ($limit) + ', pattern: \'' + (it.util.escapeQuotes($pgProperty)) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have ' + ($moreOrLess) + ' than ' + ($limit) + ' properties matching pattern "' + (it.util.escapeQuotes($pgProperty)) + '"\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - if ($pgMax !== undefined) { - out += ' else '; - } - } - if ($pgMax !== undefined) { - var $limit = $pgMax, - $reason = 'maximum', - $moreOrLess = 'more'; - out += ' ' + ($valid) + ' = pgPropCount' + ($lvl) + ' <= ' + ($pgMax) + '; '; - $errSchemaPath = it.errSchemaPath + '/patternGroups/maximum'; - out += ' if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('patternGroups') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { reason: \'' + ($reason) + '\', limit: ' + ($limit) + ', pattern: \'' + (it.util.escapeQuotes($pgProperty)) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have ' + ($moreOrLess) + ' than ' + ($limit) + ' properties matching pattern "' + (it.util.escapeQuotes($pgProperty)) + '"\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - } - $errSchemaPath = $currErrSchemaPath; - if ($breakOnError) { - out += ' if (' + ($valid) + ') { '; - $closingBraces += '}'; - } - } - } + const binEntries = yield (0, (_run || _load_run()).getBinEntries)(config); + + const binName = args[0]; + const binPath = binEntries.get(binName); + + if (binPath) { + reporter.log(binPath, { force: true }); + } else { + reporter.error(reporter.lang('packageBinaryNotFound', binName)); } } - } - if ($breakOnError) { - out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; - } - out = it.util.cleanUpCode(out); - return out; + }); + + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; + +var _run; + +function _load_run() { + return _run = __webpack_require__(354); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const path = __webpack_require__(0); + +function hasWrapper(commander) { + return false; } +function setFlags(commander) { + commander.description('Displays the location of the yarn bin folder.'); +} /***/ }), /* 495 */ @@ -92534,87 +91686,119 @@ module.exports = function generate_properties(it, $keyword, $ruleType) { "use strict"; -module.exports = function generate_propertyNames(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $errs = 'errs__' + $lvl; - var $it = it.util.copy(it); - var $closingBraces = ''; - $it.level++; - var $nextValid = 'valid' + $it.level; - if (it.util.schemaHasRules($schema, it.RULES.all)) { - $it.schema = $schema; - $it.schemaPath = $schemaPath; - $it.errSchemaPath = $errSchemaPath; - var $key = 'key' + $lvl, - $idx = 'idx' + $lvl, - $i = 'i' + $lvl, - $invalidName = '\' + ' + $key + ' + \'', - $dataNxt = $it.dataLevel = it.dataLevel + 1, - $nextData = 'data' + $dataNxt, - $dataProperties = 'dataProperties' + $lvl, - $ownProperties = it.opts.ownProperties, - $currentBaseId = it.baseId; - out += ' var ' + ($errs) + ' = errors; '; - if ($ownProperties) { - out += ' var ' + ($dataProperties) + ' = undefined; '; - } - if ($ownProperties) { - out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; '; - } else { - out += ' for (var ' + ($key) + ' in ' + ($data) + ') { '; - } - out += ' var startErrs' + ($lvl) + ' = errors; '; - var $passData = $key; - var $wasComposite = it.compositeRule; - it.compositeRule = $it.compositeRule = true; - var $code = it.validate($it); - $it.baseId = $currentBaseId; - if (it.util.varOccurences($code, $nextData) < 2) { - out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' '; - } else { - out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' '; - } - it.compositeRule = $it.compositeRule = $wasComposite; - out += ' if (!' + ($nextValid) + ') { for (var ' + ($i) + '=startErrs' + ($lvl) + '; ' + ($i) + ' 2) { + return false; } - out += ' } '; - } else { - out += ' {} '; + const key = args[0]; + var _args$ = args[1]; + const val = _args$ === undefined ? true : _args$; + + const yarnConfig = config.registries.yarn; + yield yarnConfig.saveHomeConfig({ [key]: val }); + reporter.success(reporter.lang('configSet', key, val)); + return true; + })(); + }, + + get(config, reporter, flags, args) { + if (args.length !== 1) { + return false; } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError(vErrors); '; - } else { - out += ' validate.errors = vErrors; return false; '; + + reporter.log(String(config.getOption(args[0])), { force: true }); + return true; + }, + + delete: (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + if (args.length !== 1) { + return false; } + + const key = args[0]; + const yarnConfig = config.registries.yarn; + yield yarnConfig.saveHomeConfig({ [key]: undefined }); + reporter.success(reporter.lang('configDelete', key)); + return true; + }); + + function _delete(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); } - if ($breakOnError) { - out += ' break; '; + + return _delete; + })(), + + list(config, reporter, flags, args) { + if (args.length) { + return false; } - out += ' } }'; - } - if ($breakOnError) { - out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {'; + + reporter.info(reporter.lang('configYarn')); + reporter.inspect(config.registries.yarn.config); + + reporter.info(reporter.lang('configNpm')); + reporter.inspect(config.registries.npm.config); + + return true; + }, + + current(config, reporter, flags, args) { + if (args.length) { + return false; + } + + reporter.log(JSON.stringify(config, CONFIG_KEYS, 2), { force: true }); + + return true; } - out = it.util.cleanUpCode(out); - return out; -} +}); +const run = _buildSubCommands.run, + examples = _buildSubCommands.examples; +exports.run = run; +exports.examples = examples; /***/ }), /* 496 */ @@ -92622,129 +91806,139 @@ module.exports = function generate_propertyNames(it, $keyword, $ruleType) { "use strict"; -module.exports = function generate_ref(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $async, $refCode; - if ($schema == '#' || $schema == '#/') { - if (it.isRoot) { - $async = it.async; - $refCode = 'validate'; - } else { - $async = it.root.schema.$async === true; - $refCode = 'root.refVal[0]'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); +} + +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const builderName = args[0], + rest = args.slice(1); + + + if (!builderName) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('invalidPackageName')); } - } else { - var $refVal = it.resolveRef(it.baseId, $schema, it.isRoot); - if ($refVal === undefined) { - var $message = it.MissingRefError.message(it.baseId, $schema); - if (it.opts.missingRefs == 'fail') { - it.logger.error($message); - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('$ref') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { ref: \'' + (it.util.escapeQuotes($schema)) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \'can\\\'t resolve reference ' + (it.util.escapeQuotes($schema)) + '\' '; - } - if (it.opts.verbose) { - out += ' , schema: ' + (it.util.toQuotedString($schema)) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - if ($breakOnError) { - out += ' if (false) { '; - } - } else if (it.opts.missingRefs == 'ignore') { - it.logger.warn($message); - if ($breakOnError) { - out += ' if (true) { '; - } - } else { - throw new it.MissingRefError(it.baseId, $schema, $message); - } - } else if ($refVal.inline) { - var $it = it.util.copy(it); - $it.level++; - var $nextValid = 'valid' + $it.level; - $it.schema = $refVal.schema; - $it.schemaPath = ''; - $it.errSchemaPath = $schema; - var $code = it.validate($it).replace(/validate\.schema/g, $refVal.code); - out += ' ' + ($code) + ' '; - if ($breakOnError) { - out += ' if (' + ($nextValid) + ') { '; - } + + var _coerceCreatePackageN = coerceCreatePackageName(builderName); + + const packageName = _coerceCreatePackageN.fullName, + commandName = _coerceCreatePackageN.name; + + + const linkLoc = path.join(config.linkFolder, commandName); + if (yield (_fs || _load_fs()).exists(linkLoc)) { + reporter.info(reporter.lang('linkUsing', packageName)); } else { - $async = $refVal.$async === true; - $refCode = $refVal.code; + yield (0, (_global || _load_global()).run)(config, reporter, {}, ['add', packageName]); } + + const binFolder = yield (0, (_global || _load_global()).getBinFolder)(config, {}); + const command = path.resolve(binFolder, commandName); + const env = yield (0, (_executeLifecycleScript || _load_executeLifecycleScript()).makeEnv)('create', config.cwd, config); + + yield (_child || _load_child()).spawn(command, rest, { stdio: `inherit`, shell: true, env }); + }); + + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; +exports.parsePackageName = parsePackageName; +exports.coerceCreatePackageName = coerceCreatePackageName; + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); +} + +var _child; + +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); +} + +var _executeLifecycleScript; + +function _load_executeLifecycleScript() { + return _executeLifecycleScript = __webpack_require__(111); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} + +var _global; + +function _load_global() { + return _global = __webpack_require__(121); +} + +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 path = __webpack_require__(0); + +function setFlags(commander) { + commander.description('Creates new projects from any create-* starter kits.'); +} + +function hasWrapper(commander, args) { + return true; +} + +function parsePackageName(str) { + if (str.charAt(0) === '/') { + throw new Error(`Name should not start with "/", got "${str}"`); } - if ($refCode) { - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; - if (it.opts.passContext) { - out += ' ' + ($refCode) + '.call(this, '; - } else { - out += ' ' + ($refCode) + '( '; - } - out += ' ' + ($data) + ', (dataPath || \'\')'; - if (it.errorPath != '""') { - out += ' + ' + (it.errorPath); - } - var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', - $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; - out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ', rootData) '; - var __callValidate = out; - out = $$outStack.pop(); - if ($async) { - if (!it.async) throw new Error('async schema referenced by sync schema'); - if ($breakOnError) { - out += ' var ' + ($valid) + '; '; - } - out += ' try { ' + (it.yieldAwait) + ' ' + (__callValidate) + '; '; - if ($breakOnError) { - out += ' ' + ($valid) + ' = true; '; - } - out += ' } catch (e) { if (!(e instanceof ValidationError)) throw e; if (vErrors === null) vErrors = e.errors; else vErrors = vErrors.concat(e.errors); errors = vErrors.length; '; - if ($breakOnError) { - out += ' ' + ($valid) + ' = false; '; - } - out += ' } '; - if ($breakOnError) { - out += ' if (' + ($valid) + ') { '; - } - } else { - out += ' if (!' + (__callValidate) + ') { if (vErrors === null) vErrors = ' + ($refCode) + '.errors; else vErrors = vErrors.concat(' + ($refCode) + '.errors); errors = vErrors.length; } '; - if ($breakOnError) { - out += ' else { '; - } - } + if (str.charAt(0) === '.') { + throw new Error(`Name should not start with ".", got "${str}"`); } - return out; + const parts = str.split('/'); + const isScoped = str.charAt(0) === '@'; + if (isScoped && parts[0] === '@') { + throw new Error(`Scope should not be empty, got "${str}"`); + } + const scope = isScoped ? parts[0] : ''; + const name = parts[isScoped ? 1 : 0] || ''; + const path = parts.slice(isScoped ? 2 : 1).join('/'); + const fullName = [scope, name].filter(Boolean).join('/'); + const full = [scope, name, path].filter(Boolean).join('/'); + + return { fullName, name, scope, path, full }; } +function coerceCreatePackageName(str) { + const pkgNameObj = parsePackageName(str); + const coercedName = pkgNameObj.name !== '' ? `create-${pkgNameObj.name}` : `create`; + const coercedPkgNameObj = (0, (_extends2 || _load_extends()).default)({}, pkgNameObj, { + name: coercedName, + fullName: [pkgNameObj.scope, coercedName].filter(Boolean).join('/'), + full: [pkgNameObj.scope, coercedName, pkgNameObj.path].filter(Boolean).join('/') + }); + return coercedPkgNameObj; +} /***/ }), /* 497 */ @@ -92752,2852 +91946,2194 @@ module.exports = function generate_ref(it, $keyword, $ruleType) { "use strict"; -module.exports = function generate_required(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - var $vSchema = 'schema' + $lvl; - if (!$isData) { - if ($schema.length < it.opts.loopRequired && it.schema.properties && Object.keys(it.schema.properties).length) { - var $required = []; - var arr1 = $schema; - if (arr1) { - var $property, i1 = -1, - l1 = arr1.length - 1; - while (i1 < l1) { - $property = arr1[i1 += 1]; - var $propertySch = it.schema.properties[$property]; - if (!($propertySch && it.util.schemaHasRules($propertySch, it.RULES.all))) { - $required[$required.length] = $property; - } - } - } - } else { - var $required = $schema; - } - } - if ($isData || $required.length) { - var $currentErrorPath = it.errorPath, - $loopRequired = $isData || $required.length >= it.opts.loopRequired, - $ownProperties = it.opts.ownProperties; - if ($breakOnError) { - out += ' var missing' + ($lvl) + '; '; - if ($loopRequired) { - if (!$isData) { - out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; - } - var $i = 'i' + $lvl, - $propertyPath = 'schema' + $lvl + '[' + $i + ']', - $missingProperty = '\' + ' + $propertyPath + ' + \''; - if (it.opts._errorDataPathProperty) { - it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); - } - out += ' var ' + ($valid) + ' = true; '; - if ($isData) { - out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {'; - } - out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { ' + ($valid) + ' = ' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] !== undefined '; - if ($ownProperties) { - out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; - } - out += '; if (!' + ($valid) + ') break; } '; - if ($isData) { - out += ' } '; - } - out += ' if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else { '; - } else { - out += ' if ( '; - var arr2 = $required; - if (arr2) { - var $propertyKey, $i = -1, - l2 = arr2.length - 1; - while ($i < l2) { - $propertyKey = arr2[$i += 1]; - if ($i) { - out += ' || '; - } - var $prop = it.util.getProperty($propertyKey), - $useData = $data + $prop; - out += ' ( ( ' + ($useData) + ' === undefined '; - if ($ownProperties) { - out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; - } - out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) '; - } - } - out += ') { '; - var $propertyPath = 'missing' + $lvl, - $missingProperty = '\' + ' + $propertyPath + ' + \''; - if (it.opts._errorDataPathProperty) { - it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath; - } - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } else { '; - } - } else { - if ($loopRequired) { - if (!$isData) { - out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + '; '; - } - var $i = 'i' + $lvl, - $propertyPath = 'schema' + $lvl + '[' + $i + ']', - $missingProperty = '\' + ' + $propertyPath + ' + \''; - if (it.opts._errorDataPathProperty) { - it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers); - } - if ($isData) { - out += ' if (' + ($vSchema) + ' && !Array.isArray(' + ($vSchema) + ')) { var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } else if (' + ($vSchema) + ' !== undefined) { '; - } - out += ' for (var ' + ($i) + ' = 0; ' + ($i) + ' < ' + ($vSchema) + '.length; ' + ($i) + '++) { if (' + ($data) + '[' + ($vSchema) + '[' + ($i) + ']] === undefined '; - if ($ownProperties) { - out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + ']) '; - } - out += ') { var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } } '; - if ($isData) { - out += ' } '; - } - } else { - var arr3 = $required; - if (arr3) { - var $propertyKey, i3 = -1, - l3 = arr3.length - 1; - while (i3 < l3) { - $propertyKey = arr3[i3 += 1]; - var $prop = it.util.getProperty($propertyKey), - $missingProperty = it.util.escapeQuotes($propertyKey), - $useData = $data + $prop; - if (it.opts._errorDataPathProperty) { - it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); - } - out += ' if ( ' + ($useData) + ' === undefined '; - if ($ownProperties) { - out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') '; - } - out += ') { var err = '; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } '; - if (it.opts.messages !== false) { - out += ' , message: \''; - if (it.opts._errorDataPathProperty) { - out += 'is a required property'; - } else { - out += 'should have required property \\\'' + ($missingProperty) + '\\\''; - } - out += '\' '; - } - if (it.opts.verbose) { - out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } '; - } - } - } - } - it.errorPath = $currentErrorPath; - } else if ($breakOnError) { - out += ' if (true) {'; - } - return out; -} +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = undefined; -/***/ }), -/* 498 */ -/***/ (function(module, exports, __webpack_require__) { +var _asyncToGenerator2; -"use strict"; +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} -module.exports = function generate_uniqueItems(it, $keyword, $ruleType) { - var out = ' '; - var $lvl = it.level; - var $dataLvl = it.dataLevel; - var $schema = it.schema[$keyword]; - var $schemaPath = it.schemaPath + it.util.getProperty($keyword); - var $errSchemaPath = it.errSchemaPath + '/' + $keyword; - var $breakOnError = !it.opts.allErrors; - var $data = 'data' + ($dataLvl || ''); - var $valid = 'valid' + $lvl; - var $isData = it.opts.$data && $schema && $schema.$data, - $schemaValue; - if ($isData) { - out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; '; - $schemaValue = 'schema' + $lvl; - } else { - $schemaValue = $schema; - } - if (($schema || $isData) && it.opts.uniqueItems !== false) { - if ($isData) { - out += ' var ' + ($valid) + '; if (' + ($schemaValue) + ' === false || ' + ($schemaValue) + ' === undefined) ' + ($valid) + ' = true; else if (typeof ' + ($schemaValue) + ' != \'boolean\') ' + ($valid) + ' = false; else { '; - } - out += ' var ' + ($valid) + ' = true; if (' + ($data) + '.length > 1) { var i = ' + ($data) + '.length, j; outer: for (;i--;) { for (j = i; j--;) { if (equal(' + ($data) + '[i], ' + ($data) + '[j])) { ' + ($valid) + ' = false; break outer; } } } } '; - if ($isData) { - out += ' } '; - } - out += ' if (!' + ($valid) + ') { '; - var $$outStack = $$outStack || []; - $$outStack.push(out); - out = ''; /* istanbul ignore else */ - if (it.createErrors !== false) { - out += ' { keyword: \'' + ('uniqueItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { i: i, j: j } '; - if (it.opts.messages !== false) { - out += ' , message: \'should NOT have duplicate items (items ## \' + j + \' and \' + i + \' are identical)\' '; - } - if (it.opts.verbose) { - out += ' , schema: '; - if ($isData) { - out += 'validate.schema' + ($schemaPath); - } else { - out += '' + ($schema); - } - out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; - } - out += ' } '; - } else { - out += ' {} '; - } - var __err = out; - out = $$outStack.pop(); - if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */ - if (it.async) { - out += ' throw new ValidationError([' + (__err) + ']); '; - } else { - out += ' validate.errors = [' + (__err) + ']; return false; '; - } - } else { - out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; - } - out += ' } '; - if ($breakOnError) { - out += ' else { '; - } - } else { - if ($breakOnError) { - out += ' if (true) { '; +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const env = yield (0, (_executeLifecycleScript || _load_executeLifecycleScript()).makeEnv)(`exec`, config.cwd, config); + + if (args.length < 1) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('execMissingCommand')); } - } - return out; -} + const execName = args[0], + rest = args.slice(1); -/***/ }), -/* 499 */ -/***/ (function(module, exports, __webpack_require__) { + yield (_child || _load_child()).spawn(execName, rest, { stdio: 'inherit', env }); + }); -"use strict"; + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; -var IDENTIFIER = /^[a-z_$][a-z0-9_$-]*$/i; -var customRuleCode = __webpack_require__(485); +var _errors; -module.exports = { - add: addKeyword, - get: getKeyword, - remove: removeKeyword -}; +function _load_errors() { + return _errors = __webpack_require__(6); +} -/** - * Define custom keyword - * @this Ajv - * @param {String} keyword custom keyword, should be unique (including different from all standard, custom and macro keywords). - * @param {Object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. - * @return {Ajv} this for method chaining - */ -function addKeyword(keyword, definition) { - /* jshint validthis: true */ - /* eslint no-shadow: 0 */ - var RULES = this.RULES; +var _child; - if (RULES.keywords[keyword]) - throw new Error('Keyword ' + keyword + ' is already defined'); +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); +} - if (!IDENTIFIER.test(keyword)) - throw new Error('Keyword ' + keyword + ' is not a valid identifier'); +var _executeLifecycleScript; - if (definition) { - if (definition.macro && definition.valid !== undefined) - throw new Error('"valid" option cannot be used with macro keywords'); +function _load_executeLifecycleScript() { + return _executeLifecycleScript = __webpack_require__(111); +} - var dataType = definition.type; - if (Array.isArray(dataType)) { - var i, len = dataType.length; - for (i=0; i { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + let manifest; + if (flags.useManifest) { + manifest = yield config.readJson(flags.useManifest); + } else { + manifest = yield config.readRootManifest(); + } + if (!manifest.name) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('noName')); + } + if (!manifest.version) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('noVersion')); } - var rule = { - keyword: keyword, - definition: definition, - custom: true, - code: customRuleCode, - implements: definition.implements + const entry = { + name: manifest.name, + version: manifest.version, + resolved: flags.resolved, + registry: flags.registry || manifest._registry, + optionalDependencies: manifest.optionalDependencies, + dependencies: manifest.dependencies }; - ruleGroup.rules.push(rule); - RULES.custom[keyword] = rule; - } + const pattern = flags.pattern || `${entry.name}@${entry.version}`; + reporter.log((0, (_lockfile || _load_lockfile()).stringify)({ + [pattern]: (0, (_lockfile || _load_lockfile()).implodeEntry)(pattern, entry) + })); + }); + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); - function checkDataType(dataType) { - if (!RULES.types[dataType]) throw new Error('Unknown type ' + dataType); - } +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; - return this; +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); } +var _lockfile; -/** - * Get keyword - * @this Ajv - * @param {String} keyword pre-defined or custom keyword. - * @return {Object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise. - */ -function getKeyword(keyword) { - /* jshint validthis: true */ - var rule = this.RULES.custom[keyword]; - return rule ? rule.definition : this.RULES.keywords[keyword] || false; +function _load_lockfile() { + return _lockfile = __webpack_require__(19); } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/** - * Remove keyword - * @this Ajv - * @param {String} keyword pre-defined or custom keyword. - * @return {Ajv} this for method chaining - */ -function removeKeyword(keyword) { - /* jshint validthis: true */ - var RULES = this.RULES; - delete RULES.keywords[keyword]; - delete RULES.all[keyword]; - delete RULES.custom[keyword]; - for (var i=0; i', 'description'); + commander.option('--resolved ', 'description'); + commander.option('--registry ', 'description'); } +const examples = exports.examples = ['generate-lock-entry', 'generate-lock-entry --use-manifest ./package.json', 'generate-lock-entry --resolved local-file.tgz#hash']; /***/ }), -/* 500 */ +/* 499 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var META_SCHEMA_ID = 'http://json-schema.org/draft-06/schema'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; +exports.run = run; -module.exports = function (ajv) { - var defaultMeta = ajv._opts.defaultMeta; - var metaSchemaRef = typeof defaultMeta == 'string' - ? { $ref: defaultMeta } - : ajv.getSchema(META_SCHEMA_ID) - ? { $ref: META_SCHEMA_ID } - : {}; +var _index; - ajv.addKeyword('patternGroups', { - // implemented in properties.jst - metaSchema: { - type: 'object', - additionalProperties: { - type: 'object', - required: [ 'schema' ], - properties: { - maximum: { - type: 'integer', - minimum: 0 - }, - minimum: { - type: 'integer', - minimum: 0 - }, - schema: metaSchemaRef - }, - additionalProperties: false - } - } - }); - ajv.RULES.all.properties.implements.push('patternGroups'); -}; +function _load_index() { + return _index = _interopRequireDefault(__webpack_require__(334)); +} +var _constants; -/***/ }), -/* 501 */ -/***/ (function(module, exports) { +function _load_constants() { + return _constants = _interopRequireWildcard(__webpack_require__(8)); +} -module.exports = {"$schema":"http://json-schema.org/draft-06/schema#","$id":"https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/$data.json#","description":"Meta-schema for $data reference (JSON-schema extension proposal)","type":"object","required":["$data"],"properties":{"$data":{"type":"string","anyOf":[{"format":"relative-json-pointer"},{"format":"json-pointer"}]}},"additionalProperties":false} +var _misc; -/***/ }), -/* 502 */ -/***/ (function(module, exports) { +function _load_misc() { + return _misc = __webpack_require__(18); +} -module.exports = {"$schema":"http://json-schema.org/draft-06/schema#","$id":"http://json-schema.org/draft-06/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"examples":{"type":"array","items":{}},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":{},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":{}} +var _aliases; -/***/ }), -/* 503 */ -/***/ (function(module, exports, __webpack_require__) { +function _load_aliases() { + return _aliases = _interopRequireDefault(__webpack_require__(346)); +} -"use strict"; +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 }; } -var traverse = module.exports = function (schema, opts, cb) { - if (typeof opts == 'function') { - cb = opts; - opts = {}; - } - _traverse(opts, cb, schema, '', schema); -}; +const chalk = __webpack_require__(30); +function hasWrapper(flags, args) { + return false; +} -traverse.keywords = { - additionalItems: true, - items: true, - contains: true, - additionalProperties: true, - propertyNames: true, - not: true -}; +function setFlags(commander) { + commander.description('Displays help information.'); +} -traverse.arrayKeywords = { - items: true, - allOf: true, - anyOf: true, - oneOf: true -}; +function run(config, reporter, commander, args) { + if (args.length) { + const commandName = args.shift(); + if (Object.prototype.hasOwnProperty.call((_index || _load_index()).default, commandName)) { + const command = (_index || _load_index()).default[commandName]; + if (command) { + command.setFlags(commander); + const examples = (command.examples || []).map(example => ` $ yarn ${example}`); + if (examples.length) { + commander.on('--help', () => { + reporter.log(reporter.lang('helpExamples', reporter.rawText(examples.join('\n')))); + }); + } + // eslint-disable-next-line yarn-internal/warn-language + commander.on('--help', () => reporter.log(' ' + command.getDocsInfo + '\n')); + commander.help(); + return Promise.resolve(); + } + } + } -traverse.propsKeywords = { - definitions: true, - properties: true, - patternProperties: true, - dependencies: true -}; + commander.on('--help', () => { + const commandsText = []; + for (var _iterator = Object.keys((_index || _load_index()).default).sort((_misc || _load_misc()).sortAlpha), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; -traverse.skipKeywords = { - enum: true, - const: true, - required: true, - maximum: true, - minimum: true, - exclusiveMaximum: true, - exclusiveMinimum: true, - multipleOf: true, - maxLength: true, - minLength: true, - pattern: true, - format: true, - maxItems: true, - minItems: true, - uniqueItems: true, - maxProperties: true, - minProperties: true -}; + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + const name = _ref; -function _traverse(opts, cb, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) { - if (schema && typeof schema == 'object' && !Array.isArray(schema)) { - cb(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex); - for (var key in schema) { - var sch = schema[key]; - if (Array.isArray(sch)) { - if (key in traverse.arrayKeywords) { - for (var i=0; i (_aliases || _load_aliases()).default[key]).indexOf(name) > -1) { + continue; + } + if ((_aliases || _load_aliases()).default[name]) { + commandsText.push(` - ${(0, (_misc || _load_misc()).hyphenate)(name)} / ${(_aliases || _load_aliases()).default[name]}`); + } else { + commandsText.push(` - ${(0, (_misc || _load_misc()).hyphenate)(name)}`); } } - } -} + reporter.log(reporter.lang('helpCommands', reporter.rawText(commandsText.join('\n')))); + reporter.log(reporter.lang('helpCommandsMore', reporter.rawText(chalk.bold('yarn help COMMAND')))); + reporter.log(reporter.lang('helpLearnMore', reporter.rawText(chalk.bold((_constants || _load_constants()).YARN_DOCS)))); + }); + commander.options.sort((_misc || _load_misc()).sortOptionsByFlags); -function escapeJsonPtr(str) { - return str.replace(/~/g, '~0').replace(/\//g, '~1'); + commander.help(); + return Promise.resolve(); } - /***/ }), -/* 504 */ +/* 500 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const x = module.exports; -const ESC = '\u001B['; -const OSC = '\u001B]'; -const BEL = '\u0007'; -const SEP = ';'; -const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal'; -x.cursorTo = (x, y) => { - if (typeof x !== 'number') { - throw new TypeError('The `x` argument is required'); - } +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = exports.Import = exports.noArguments = undefined; - if (typeof y !== 'number') { - return ESC + (x + 1) + 'G'; - } +var _asyncToGenerator2; - return ESC + (y + 1) + ';' + (x + 1) + 'H'; -}; +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} -x.cursorMove = (x, y) => { - if (typeof x !== 'number') { - throw new TypeError('The `x` argument is required'); - } +let run = exports.run = (() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const imp = new Import(flags, config, reporter, new (_lockfile || _load_lockfile()).default({ cache: {} })); + yield imp.init(); + }); - let ret = ''; + return function run(_x, _x2, _x3, _x4) { + return _ref5.apply(this, arguments); + }; +})(); - if (x < 0) { - ret += ESC + (-x) + 'D'; - } else if (x > 0) { - ret += ESC + x + 'C'; - } +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; - if (y < 0) { - ret += ESC + (-y) + 'A'; - } else if (y > 0) { - ret += ESC + y + 'B'; - } +var _install; - return ret; -}; +function _load_install() { + return _install = __webpack_require__(34); +} -x.cursorUp = count => ESC + (typeof count === 'number' ? count : 1) + 'A'; -x.cursorDown = count => ESC + (typeof count === 'number' ? count : 1) + 'B'; -x.cursorForward = count => ESC + (typeof count === 'number' ? count : 1) + 'C'; -x.cursorBackward = count => ESC + (typeof count === 'number' ? count : 1) + 'D'; +var _check; -x.cursorLeft = ESC + 'G'; -x.cursorSavePosition = ESC + (isTerminalApp ? '7' : 's'); -x.cursorRestorePosition = ESC + (isTerminalApp ? '8' : 'u'); -x.cursorGetPosition = ESC + '6n'; -x.cursorNextLine = ESC + 'E'; -x.cursorPrevLine = ESC + 'F'; -x.cursorHide = ESC + '?25l'; -x.cursorShow = ESC + '?25h'; +function _load_check() { + return _check = __webpack_require__(350); +} -x.eraseLines = count => { - let clear = ''; +var _errors; - for (let i = 0; i < count; i++) { - clear += x.eraseLine + (i < count - 1 ? x.cursorUp() : ''); - } +function _load_errors() { + return _errors = __webpack_require__(6); +} - if (count) { - clear += x.cursorLeft; - } +var _index; - return clear; -}; +function _load_index() { + return _index = __webpack_require__(78); +} -x.eraseEndLine = ESC + 'K'; -x.eraseStartLine = ESC + '1K'; -x.eraseLine = ESC + '2K'; -x.eraseDown = ESC + 'J'; -x.eraseUp = ESC + '1J'; -x.eraseScreen = ESC + '2J'; -x.scrollUp = ESC + 'S'; -x.scrollDown = ESC + 'T'; +var _baseResolver; -x.clearScreen = '\u001Bc'; -x.beep = BEL; +function _load_baseResolver() { + return _baseResolver = _interopRequireDefault(__webpack_require__(123)); +} -x.link = (text, url) => { - return [ - OSC, - '8', - SEP, - SEP, - url, - BEL, - text, - OSC, - '8', - SEP, - SEP, - BEL - ].join(''); -}; +var _hostedGitResolver; -x.image = (buf, opts) => { - opts = opts || {}; +function _load_hostedGitResolver() { + return _hostedGitResolver = _interopRequireDefault(__webpack_require__(109)); +} - let ret = OSC + '1337;File=inline=1'; +var _hostedGitResolver2; - if (opts.width) { - ret += `;width=${opts.width}`; - } +function _load_hostedGitResolver2() { + return _hostedGitResolver2 = __webpack_require__(109); +} - if (opts.height) { - ret += `;height=${opts.height}`; - } +var _gistResolver; - if (opts.preserveAspectRatio === false) { - ret += ';preserveAspectRatio=0'; - } +function _load_gistResolver() { + return _gistResolver = _interopRequireDefault(__webpack_require__(214)); +} - return ret + ':' + buf.toString('base64') + BEL; -}; +var _gistResolver2; -x.iTerm = {}; +function _load_gistResolver2() { + return _gistResolver2 = __webpack_require__(214); +} -x.iTerm.setCwd = cwd => OSC + '50;CurrentDir=' + (cwd || process.cwd()) + BEL; +var _gitResolver; +function _load_gitResolver() { + return _gitResolver = _interopRequireDefault(__webpack_require__(124)); +} -/***/ }), -/* 505 */ -/***/ (function(module, exports, __webpack_require__) { +var _fileResolver; -"use strict"; +function _load_fileResolver() { + return _fileResolver = _interopRequireDefault(__webpack_require__(213)); +} -module.exports = function () { - return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g; -}; +var _packageResolver; +function _load_packageResolver() { + return _packageResolver = _interopRequireDefault(__webpack_require__(360)); +} -/***/ }), -/* 506 */ -/***/ (function(module, exports, __webpack_require__) { +var _packageRequest; -"use strict"; -/* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(608); +function _load_packageRequest() { + return _packageRequest = _interopRequireDefault(__webpack_require__(122)); +} -const wrapAnsi16 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${code + offset}m`; -}; +var _packageReference; -const wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; +function _load_packageReference() { + return _packageReference = _interopRequireDefault(__webpack_require__(359)); +} -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; +var _packageFetcher; -function assembleStyles() { - const codes = new Map(); - const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29] - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - gray: [90, 39], +function _load_packageFetcher() { + return _packageFetcher = _interopRequireWildcard(__webpack_require__(208)); +} - // Bright color - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39] - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], +var _packageLinker; - // Bright color - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] - } - }; +function _load_packageLinker() { + return _packageLinker = _interopRequireDefault(__webpack_require__(209)); +} - // Fix humans - styles.color.grey = styles.color.gray; +var _packageCompatibility; - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; +function _load_packageCompatibility() { + return _packageCompatibility = _interopRequireWildcard(__webpack_require__(207)); +} - for (const styleName of Object.keys(group)) { - const style = group[styleName]; +var _lockfile; - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); +} - group[styleName] = styles[styleName]; +var _normalizePattern9; - codes.set(style[0], style[1]); - } +function _load_normalizePattern() { + return _normalizePattern9 = __webpack_require__(37); +} - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); +var _logicalDependencyTree; - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } +function _load_logicalDependencyTree() { + return _logicalDependencyTree = __webpack_require__(550); +} - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; +var _fs; - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; +var _misc; - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; +function _load_misc() { + return _misc = _interopRequireWildcard(__webpack_require__(18)); +} - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } - - const suite = colorConvert[key]; - - if (key === 'ansi16') { - key = 'ansi'; - } - - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } - - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } - - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } - } +var _constants; - return styles; +function _load_constants() { + return _constants = __webpack_require__(8); } -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(163)(module))) - -/***/ }), -/* 507 */ -/***/ (function(module, exports) { +var _semver; -function webpackEmptyContext(req) { - throw new Error("Cannot find module '" + req + "'."); +function _load_semver() { + return _semver = _interopRequireDefault(__webpack_require__(22)); } -webpackEmptyContext.keys = function() { return []; }; -webpackEmptyContext.resolve = webpackEmptyContext; -module.exports = webpackEmptyContext; -webpackEmptyContext.id = 507; - -/***/ }), -/* 508 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; +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; } } - // global key for user preferred registration -var REGISTRATION_KEY = '@@any-promise/REGISTRATION', - // Prior registration (preferred or detected) - registered = null +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/** - * Registers the given implementation. An implementation must - * be registered prior to any call to `require("any-promise")`, - * typically on application load. - * - * If called with no arguments, will return registration in - * following priority: - * - * For Node.js: - * - * 1. Previous registration - * 2. global.Promise if node.js version >= 0.12 - * 3. Auto detected promise based on first sucessful require of - * known promise libraries. Note this is a last resort, as the - * loaded library is non-deterministic. node.js >= 0.12 will - * always use global.Promise over this priority list. - * 4. Throws error. - * - * For Browser: - * - * 1. Previous registration - * 2. window.Promise - * 3. Throws error. - * - * Options: - * - * Promise: Desired Promise constructor - * global: Boolean - Should the registration be cached in a global variable to - * allow cross dependency/bundle registration? (default true) - */ -module.exports = function(root, loadImplementation){ - return function register(implementation, opts){ - implementation = implementation || null - opts = opts || {} - // global registration unless explicitly {global: false} in options (default true) - var registerGlobal = opts.global !== false; +const invariant = __webpack_require__(9); +const path = __webpack_require__(0); +const uuid = __webpack_require__(120); +const ssri = __webpack_require__(65); +const nodeVersion = process.versions.node.split('-')[0]; - // load any previous global registration - if(registered === null && registerGlobal){ - registered = root[REGISTRATION_KEY] || null - } +const noArguments = exports.noArguments = true; - if(registered !== null - && implementation !== null - && registered.implementation !== implementation){ - // Throw error if attempting to redefine implementation - throw new Error('any-promise already defined as "'+registered.implementation+ - '". You can only register an implementation before the first '+ - ' call to require("any-promise") and an implementation cannot be changed') +class ImportResolver extends (_baseResolver || _load_baseResolver()).default { + getCwd() { + if (this.request.parentRequest) { + const parent = this.resolver.getStrictResolvedPattern(this.request.parentRequest.pattern); + invariant(parent._loc, 'expected package location'); + return path.dirname(parent._loc); } + return this.config.cwd; + } - if(registered === null){ - // use provided implementation - if(implementation !== null && typeof opts.Promise !== 'undefined'){ - registered = { - Promise: opts.Promise, - implementation: implementation - } - } else { - // require implementation if implementation is specified but not provided - registered = loadImplementation(implementation) - } + resolveHostedGit(info, Resolver) { + var _normalizePattern = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); - if(registerGlobal){ - // register preference globally in case multiple installations - root[REGISTRATION_KEY] = registered - } - } + const range = _normalizePattern.range; - return registered + const exploded = (0, (_hostedGitResolver2 || _load_hostedGitResolver2()).explodeHostedGitFragment)(range, this.reporter); + const hash = info.gitHead; + invariant(hash, 'expected package gitHead'); + const url = Resolver.getTarballUrl(exploded, hash); + info._uid = hash; + info._remote = { + resolved: url, + type: 'tarball', + registry: this.registry, + reference: url, + hash: null + }; + return info; } -} - -/***/ }), -/* 509 */ -/***/ (function(module, exports, __webpack_require__) { + resolveGist(info, Resolver) { + var _normalizePattern2 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); -"use strict"; + const range = _normalizePattern2.range; -module.exports = __webpack_require__(508)(global, loadImplementation); + var _explodeGistFragment = (0, (_gistResolver2 || _load_gistResolver2()).explodeGistFragment)(range, this.reporter); -/** - * Node.js version of loadImplementation. - * - * Requires the given implementation and returns the registration - * containing {Promise, implementation} - * - * If implementation is undefined or global.Promise, loads it - * Otherwise uses require - */ -function loadImplementation(implementation){ - var impl = null + const id = _explodeGistFragment.id; - if(shouldPreferGlobalPromise(implementation)){ - // if no implementation or env specified use global.Promise - impl = { - Promise: global.Promise, - implementation: 'global.Promise' - } - } else if(implementation){ - // if implementation specified, require it - var lib = !(function webpackMissingModule() { var e = new Error("Cannot find module \".\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()) - impl = { - Promise: lib.Promise || lib, - implementation: implementation - } - } else { - // try to auto detect implementation. This is non-deterministic - // and should prefer other branches, but this is our last chance - // to load something without throwing error - impl = tryAutoDetect() + const hash = info.gitHead; + invariant(hash, 'expected package gitHead'); + const url = `https://gist.github.com/${id}.git`; + info._uid = hash; + info._remote = { + resolved: `${url}#${hash}`, + type: 'git', + registry: this.registry, + reference: url, + hash + }; + return info; } - if(impl === null){ - throw new Error('Cannot find any-promise implementation nor'+ - ' global.Promise. You must install polyfill or call'+ - ' require("any-promise/register") with your preferred'+ - ' implementation, e.g. require("any-promise/register/bluebird")'+ - ' on application load prior to any require("any-promise").') + resolveGit(info, Resolver) { + const url = info._resolved; + const hash = info.gitHead; + invariant(url, 'expected package _resolved'); + invariant(hash, 'expected package gitHead'); + info._uid = hash; + info._remote = { + resolved: `${url}#${hash}`, + type: 'git', + registry: this.registry, + reference: url, + hash + }; + return info; } - return impl -} - -/** - * Determines if the global.Promise should be preferred if an implementation - * has not been registered. - */ -function shouldPreferGlobalPromise(implementation){ - if(implementation){ - return implementation === 'global.Promise' - } else if(typeof global.Promise !== 'undefined'){ - // Load global promise if implementation not specified - // Versions < 0.11 did not have global Promise - // Do not use for version < 0.12 as version 0.11 contained buggy versions - var version = (/v(\d+)\.(\d+)\.(\d+)/).exec(process.version) - return !(version && +version[1] == 0 && +version[2] < 12) - } + resolveFile(info, Resolver) { + var _normalizePattern3 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); - // do not have global.Promise or another implementation was specified - return false -} + const range = _normalizePattern3.range; -/** - * Look for common libs as last resort there is no guarantee that - * this will return a desired implementation or even be deterministic. - * The priority is also nearly arbitrary. We are only doing this - * for older versions of Node.js <0.12 that do not have a reasonable - * global.Promise implementation and we the user has not registered - * the preference. This preserves the behavior of any-promise <= 0.1 - * and may be deprecated or removed in the future - */ -function tryAutoDetect(){ - var libs = [ - "es6-promise", - "promise", - "native-promise-only", - "bluebird", - "rsvp", - "when", - "q", - "pinkie", - "lie", - "vow"] - var i = 0, len = libs.length - for(; i < len; i++){ - try { - return loadImplementation(libs[i]) - } catch(e){} + let loc = (_misc || _load_misc()).removePrefix(range, 'file:'); + if (!path.isAbsolute(loc)) { + loc = path.join(this.config.cwd, loc); + } + info._uid = info.version; + info._remote = { + type: 'copy', + registry: this.registry, + hash: `${uuid.v4()}-${new Date().getTime()}`, + reference: loc + }; + return info; } - return null -} - -/***/ }), -/* 510 */ -/***/ (function(module, exports, __webpack_require__) { + resolveRegistry(info) { + let url = info._resolved; + const hash = info._shasum; + invariant(url, 'expected package _resolved'); + invariant(hash, 'expected package _shasum'); + if (this.config.getOption('registry') === (_constants || _load_constants()).YARN_REGISTRY) { + url = url.replace((_constants || _load_constants()).NPM_REGISTRY_RE, (_constants || _load_constants()).YARN_REGISTRY); + } + info._uid = info.version; + info._remote = { + resolved: `${url}#${hash}`, + type: 'tarball', + registry: this.registry, + reference: url, + integrity: info._integrity ? ssri.parse(info._integrity) : ssri.fromHex(hash, 'sha1'), + hash + }; + return info; + } -"use strict"; -/*! - * arr-flatten - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + resolveImport(info) { + var _normalizePattern4 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + const range = _normalizePattern4.range; + const Resolver = (0, (_index || _load_index()).getExoticResolver)(range); + if (Resolver && Resolver.prototype instanceof (_hostedGitResolver || _load_hostedGitResolver()).default) { + return this.resolveHostedGit(info, Resolver); + } else if (Resolver && Resolver === (_gistResolver || _load_gistResolver()).default) { + return this.resolveGist(info, Resolver); + } else if (Resolver && Resolver === (_gitResolver || _load_gitResolver()).default) { + return this.resolveGit(info, Resolver); + } else if (Resolver && Resolver === (_fileResolver || _load_fileResolver()).default) { + return this.resolveFile(info, Resolver); + } + return this.resolveRegistry(info); + } -module.exports = function (arr) { - return flat(arr, []); -}; + resolveLocation(loc) { + var _this = this; -function flat(arr, res) { - var i = 0, cur; - var len = arr.length; - for (; i < len; i++) { - cur = arr[i]; - Array.isArray(cur) ? flat(cur, res) : res.push(cur); + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const info = yield _this.config.tryManifest(loc, 'npm', false); + if (!info) { + return null; + } + return _this.resolveImport(info); + })(); } - return res; -} + resolveFixedVersion(fixedVersionPattern) { + var _this2 = this; -/***/ }), -/* 511 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _normalizePattern5 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(fixedVersionPattern); -module.exports = function (arr, predicate, ctx) { - if (typeof Array.prototype.findIndex === 'function') { - return arr.findIndex(predicate, ctx); - } + const range = _normalizePattern5.range; - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } + const exoticResolver = (0, (_index || _load_index()).getExoticResolver)(range); + const manifest = exoticResolver ? yield _this2.request.findExoticVersionInfo(exoticResolver, range) : yield _this2.request.findVersionOnRegistry(fixedVersionPattern); + return manifest; + })(); + } - var list = Object(arr); - var len = list.length; + _resolveFromFixedVersions() { + var _this3 = this; - if (len === 0) { - return -1; - } + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + invariant(_this3.request instanceof ImportPackageRequest, 'request must be ImportPackageRequest'); - for (var i = 0; i < len; i++) { - if (predicate.call(ctx, list[i], i, list)) { - return i; - } - } + var _normalizePattern6 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(_this3.pattern); - return -1; -}; + const name = _normalizePattern6.name; + invariant(_this3.request.dependencyTree instanceof (_logicalDependencyTree || _load_logicalDependencyTree()).LogicalDependencyTree, 'dependencyTree on request must be LogicalDependencyTree'); + const fixedVersionPattern = _this3.request.dependencyTree.getFixedVersionPattern(name, _this3.request.parentNames); + const info = yield _this3.config.getCache(`import-resolver-${fixedVersionPattern}`, function () { + return _this3.resolveFixedVersion(fixedVersionPattern); + }); + if (info) { + return info; + } + throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('importResolveFailed', name, _this3.getCwd())); + })(); + } -/***/ }), -/* 512 */ -/***/ (function(module, exports, __webpack_require__) { + _resolveFromNodeModules() { + var _this4 = this; -"use strict"; + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _normalizePattern7 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(_this4.pattern); + const name = _normalizePattern7.name; -var rawAsap = __webpack_require__(513); -var freeTasks = []; + let cwd = _this4.getCwd(); + while (!path.relative(_this4.config.cwd, cwd).startsWith('..')) { + const loc = path.join(cwd, 'node_modules', name); + const info = yield _this4.config.getCache(`import-resolver-${loc}`, function () { + return _this4.resolveLocation(loc); + }); + if (info) { + return info; + } + cwd = path.resolve(cwd, '../..'); + } + throw new (_errors || _load_errors()).MessageError(_this4.reporter.lang('importResolveFailed', name, _this4.getCwd())); + })(); + } -/** - * Calls a task as soon as possible after returning, in its own event, with - * priority over IO events. An exception thrown in a task can be handled by - * `process.on("uncaughtException") or `domain.on("error")`, but will otherwise - * crash the process. If the error is handled, all subsequent tasks will - * resume. - * - * @param {{call}} task A callable object, typically a function that takes no - * arguments. - */ -module.exports = asap; -function asap(task) { - var rawTask; - if (freeTasks.length) { - rawTask = freeTasks.pop(); + resolve() { + if (this.request instanceof ImportPackageRequest && this.request.dependencyTree) { + return this._resolveFromFixedVersions(); } else { - rawTask = new RawTask(); + return this._resolveFromNodeModules(); } - rawTask.task = task; - rawTask.domain = process.domain; - rawAsap(rawTask); -} - -function RawTask() { - this.task = null; - this.domain = null; + } } -RawTask.prototype.call = function () { - if (this.domain) { - this.domain.enter(); - } - var threw = true; - try { - this.task.call(); - threw = false; - // If the task throws an exception (presumably) Node.js restores the - // domain stack for the next event. - if (this.domain) { - this.domain.exit(); - } - } finally { - // We use try/finally and a threw flag to avoid messing up stack traces - // when we catch and release errors. - if (threw) { - // In Node.js, uncaught exceptions are considered fatal errors. - // Re-throw them to interrupt flushing! - // Ensure that flushing continues if an uncaught exception is - // suppressed listening process.on("uncaughtException") or - // domain.on("error"). - rawAsap.requestFlush(); - } - // If the task threw an error, we do not want to exit the domain here. - // Exiting the domain would prevent the domain from catching the error. - this.task = null; - this.domain = null; - freeTasks.push(this); - } -}; - - - -/***/ }), -/* 513 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +class ImportPackageRequest extends (_packageRequest || _load_packageRequest()).default { + constructor(req, dependencyTree, resolver) { + super(req, resolver); + this.import = this.parentRequest instanceof ImportPackageRequest ? this.parentRequest.import : true; + this.dependencyTree = dependencyTree; + } + getRootName() { + return this.resolver instanceof ImportPackageResolver && this.resolver.rootName || 'root'; + } -var domain; // The domain module is executed on demand -var hasSetImmediate = typeof setImmediate === "function"; + getParentHumanName() { + return [this.getRootName()].concat(this.parentNames).join(' > '); + } -// Use the fastest means possible to execute a task in its own turn, with -// priority over other events including network IO events in Node.js. -// -// An exception thrown by a task will permanently interrupt the processing of -// subsequent tasks. The higher level `asap` function ensures that if an -// exception is thrown by a task, that the task queue will continue flushing as -// soon as possible, but if you use `rawAsap` directly, you are responsible to -// either ensure that no exceptions are thrown from your task, or to manually -// call `rawAsap.requestFlush` if an exception is thrown. -module.exports = rawAsap; -function rawAsap(task) { - if (!queue.length) { - requestFlush(); - flushing = true; + reportResolvedRangeMatch(info, resolved) { + if (info.version === resolved.version) { + return; } - // Avoids a function call - queue[queue.length] = task; -} + this.reporter.warn(this.reporter.lang('importResolvedRangeMatch', resolved.version, resolved.name, info.version, this.getParentHumanName())); + } -var queue = []; -// Once a flush has been requested, no further calls to `requestFlush` are -// necessary until the next `flush` completes. -var flushing = false; -// The position of the next task to execute in the task queue. This is -// preserved between calls to `flush` so that it can be resumed if -// a task throws an exception. -var index = 0; -// If a task schedules additional tasks recursively, the task queue can grow -// unbounded. To prevent memory excaustion, the task queue will periodically -// truncate already-completed tasks. -var capacity = 1024; + _findResolvedManifest(info) { + var _normalizePattern8 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); -// The flush function processes all tasks that have been scheduled with -// `rawAsap` unless and until one of those tasks throws an exception. -// If a task throws an exception, `flush` ensures that its state will remain -// consistent and will resume where it left off when called again. -// However, `flush` does not make any arrangements to be called again if an -// exception is thrown. -function flush() { - while (index < queue.length) { - var currentIndex = index; - // Advance the index before calling the task. This ensures that we will - // begin flushing on the next task the task throws an error. - index = index + 1; - queue[currentIndex].call(); - // Prevent leaking memory for long chains of recursive calls to `asap`. - // If we call `asap` within tasks scheduled by `asap`, the queue will - // grow, but to avoid an O(n) walk for every task we execute, we don't - // shift tasks off the queue after they have been executed. - // Instead, we periodically shift 1024 tasks off the queue. - if (index > capacity) { - // Manually shift all values starting at the index back to the - // beginning of the queue. - for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { - queue[scan] = queue[scan + index]; - } - queue.length -= index; - index = 0; - } - } - queue.length = 0; - index = 0; - flushing = false; -} + const range = _normalizePattern8.range, + name = _normalizePattern8.name; -rawAsap.requestFlush = requestFlush; -function requestFlush() { - // Ensure flushing is not bound to any domain. - // It is not sufficient to exit the domain, because domains exist on a stack. - // To execute code outside of any domain, the following dance is necessary. - var parentDomain = process.domain; - if (parentDomain) { - if (!domain) { - // Lazy execute the domain module. - // Only employed if the user elects to use domains. - domain = __webpack_require__(965); - } - domain.active = process.domain = null; + const solvedRange = (_semver || _load_semver()).default.validRange(range) ? info.version : range; + const resolved = this.resolver.getExactVersionMatch(name, solvedRange, info); + if (resolved) { + return resolved; } + invariant(info._remote, 'expected package remote'); + const ref = new (_packageReference || _load_packageReference()).default(this, info, info._remote); + info._reference = ref; + return info; + } - // `setImmediate` is slower that `process.nextTick`, but `process.nextTick` - // cannot handle recursion. - // `requestFlush` will only be called recursively from `asap.js`, to resume - // flushing after an error is thrown into a domain. - // Conveniently, `setImmediate` was introduced in the same version - // `process.nextTick` started throwing recursion errors. - if (flushing && hasSetImmediate) { - setImmediate(flush); - } else { - process.nextTick(flush); - } + resolveToExistingVersion(info) { + const resolved = this._findResolvedManifest(info); + invariant(resolved, 'should have found a resolved reference'); + const ref = resolved._reference; + invariant(ref, 'should have a package reference'); + ref.addRequest(this); + ref.addPattern(this.pattern, resolved); + ref.addOptional(this.optional); + } - if (parentDomain) { - domain.active = process.domain = parentDomain; + findVersionInfo() { + if (!this.import) { + this.reporter.verbose(this.reporter.lang('skippingImport', this.pattern, this.getParentHumanName())); + return super.findVersionInfo(); } + const resolver = new ImportResolver(this, this.pattern); + return resolver.resolve().catch(() => { + this.import = false; + this.reporter.warn(this.reporter.lang('importFailed', this.pattern, this.getParentHumanName())); + return super.findVersionInfo(); + }); + } } +class ImportPackageResolver extends (_packageResolver || _load_packageResolver()).default { + constructor(config, lockfile) { + super(config, lockfile); + this.next = []; + this.rootName = 'root'; + } -/***/ }), -/* 514 */ -/***/ (function(module, exports, __webpack_require__) { + find(req) { + this.next.push(req); + return Promise.resolve(); + } -// Copyright 2011 Mark Cavage All rights reserved. + findOne(req) { + var _this5 = this; -var errors = __webpack_require__(205); -var types = __webpack_require__(206); + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (_this5.activity) { + _this5.activity.tick(req.pattern); + } + const request = new ImportPackageRequest(req, _this5.dependencyTree, _this5); + yield request.find({ fresh: false }); + })(); + } -var Reader = __webpack_require__(515); -var Writer = __webpack_require__(516); + findAll(deps) { + var _this6 = this; + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + yield Promise.all(deps.map(function (dep) { + return _this6.findOne(dep); + })); + deps = _this6.next; + _this6.next = []; + if (!deps.length) { + // all required package versions have been discovered, so now packages that + // resolved to existing versions can be resolved to their best available version + _this6.resolvePackagesWithExistingVersions(); + return; + } + yield _this6.findAll(deps); + })(); + } -// --- Exports + resetOptional() { + for (const pattern in this.patterns) { + const ref = this.patterns[pattern]._reference; + invariant(ref, 'expected reference'); + ref.optional = null; + for (var _iterator = ref.requests, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; -module.exports = { + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } - Reader: Reader, + const req = _ref; - Writer: Writer + ref.addOptional(req.optional); + } + } + } -}; + init(deps, { isFlat, isFrozen, workspaceLayout } = { isFlat: false, isFrozen: false, workspaceLayout: undefined }) { + var _this7 = this; -for (var t in types) { - if (types.hasOwnProperty(t)) - module.exports[t] = types[t]; -} -for (var e in errors) { - if (errors.hasOwnProperty(e)) - module.exports[e] = errors[e]; + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this7.flat = Boolean(isFlat); + const activity = _this7.activity = _this7.reporter.activity(); + yield _this7.findAll(deps); + _this7.resetOptional(); + activity.end(); + _this7.activity = null; + })(); + } } +class Import extends (_install || _load_install()).Install { + constructor(flags, config, reporter, lockfile) { + super(flags, config, reporter, lockfile); + this.resolver = new ImportPackageResolver(this.config, this.lockfile); + this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); + } + createLogicalDependencyTree(packageJson, packageLock) { + invariant(packageJson, 'package.json should exist'); + invariant(packageLock, 'package-lock.json should exist'); + invariant(this.resolver instanceof ImportPackageResolver, 'resolver should be an ImportPackageResolver'); + try { + this.resolver.dependencyTree = new (_logicalDependencyTree || _load_logicalDependencyTree()).LogicalDependencyTree(packageJson, packageLock); + } catch (e) { + throw new (_errors || _load_errors()).MessageError(this.reporter.lang('importSourceFilesCorrupted')); + } + } + getExternalLockfileContents() { + var _this8 = this; -/***/ }), -/* 515 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2011 Mark Cavage All rights reserved. + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + try { + var _ref2 = yield Promise.all([(_fs || _load_fs()).readFile(path.join(_this8.config.cwd, (_constants || _load_constants()).NODE_PACKAGE_JSON)), (_fs || _load_fs()).readFile(path.join(_this8.config.cwd, (_constants || _load_constants()).NPM_LOCK_FILENAME))]); -var assert = __webpack_require__(28); -var Buffer = __webpack_require__(15).Buffer; + const packageJson = _ref2[0], + packageLock = _ref2[1]; -var ASN1 = __webpack_require__(206); -var errors = __webpack_require__(205); + return { packageJson, packageLock }; + } catch (e) { + return { packageJson: null, packageLock: null }; + } + })(); + } + init() { + var _this9 = this; + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (yield (_fs || _load_fs()).exists(path.join(_this9.config.cwd, (_constants || _load_constants()).LOCKFILE_FILENAME))) { + throw new (_errors || _load_errors()).MessageError(_this9.reporter.lang('lockfileExists')); + } -// --- Globals + var _ref3 = yield _this9.getExternalLockfileContents(); -var newInvalidAsn1Error = errors.newInvalidAsn1Error; + const packageJson = _ref3.packageJson, + packageLock = _ref3.packageLock; + const importSource = packageJson && packageLock && (_semver || _load_semver()).default.satisfies(nodeVersion, '>=5.0.0') ? 'package-lock.json' : 'node_modules'; + if (importSource === 'package-lock.json') { + _this9.reporter.info(_this9.reporter.lang('importPackageLock')); + _this9.createLogicalDependencyTree(packageJson, packageLock); + } + if (importSource === 'node_modules') { + _this9.reporter.info(_this9.reporter.lang('importNodeModules')); + yield (0, (_check || _load_check()).verifyTreeCheck)(_this9.config, _this9.reporter, {}, []); + } + var _ref4 = yield _this9.fetchRequestFromCwd(); -// --- API + const requests = _ref4.requests, + patterns = _ref4.patterns, + manifest = _ref4.manifest; -function Reader(data) { - if (!data || !Buffer.isBuffer(data)) - throw new TypeError('data must be a node Buffer'); + if (manifest.name && _this9.resolver instanceof ImportPackageResolver) { + _this9.resolver.rootName = manifest.name; + } + yield _this9.resolver.init(requests, { isFlat: _this9.flags.flat, isFrozen: _this9.flags.frozenLockfile }); + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this9.resolver.getManifests(), _this9.config); + _this9.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this9.resolver.getManifests(), _this9.config, _this9.flags.ignoreEngines); + yield _this9.linker.resolvePeerModules(); + yield _this9.saveLockfileAndIntegrity(patterns); + return patterns; + })(); + } +} - this._buf = data; - this._size = data.length; +exports.Import = Import; +function setFlags(commander) { + commander.description('Generates yarn.lock from an npm package-lock.json file or an existing npm-installed node_modules folder.'); +} - // These hold the "current" state - this._len = 0; - this._offset = 0; +function hasWrapper(commander, args) { + return true; } -Object.defineProperty(Reader.prototype, 'length', { - enumerable: true, - get: function () { return (this._len); } -}); +/***/ }), +/* 501 */ +/***/ (function(module, exports, __webpack_require__) { -Object.defineProperty(Reader.prototype, 'offset', { - enumerable: true, - get: function () { return (this._offset); } -}); +"use strict"; -Object.defineProperty(Reader.prototype, 'remain', { - get: function () { return (this._size - this._offset); } -}); -Object.defineProperty(Reader.prototype, 'buffer', { - get: function () { return (this._buf.slice(this._offset)); } +Object.defineProperty(exports, "__esModule", { + value: true }); +exports.run = undefined; +var _asyncToGenerator2; -/** - * Reads a single byte and advances offset; you can pass in `true` to make this - * a "peek" operation (i.e., get the byte, but don't advance the offset). - * - * @param {Boolean} peek true means don't move offset. - * @return {Number} the next byte, null if not enough data. - */ -Reader.prototype.readByte = function (peek) { - if (this._size - this._offset < 1) - return null; - - var b = this._buf[this._offset] & 0xff; +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} - if (!peek) - this._offset += 1; +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + if (args.length > 2) { + reporter.error(reporter.lang('tooManyArguments', 2)); + return; + } - return b; -}; + let packageName = args.shift() || '.'; + // Handle the case when we are referencing a local package. + if (packageName === '.') { + packageName = (yield config.readRootManifest()).name; + } -Reader.prototype.peek = function () { - return this.readByte(true); -}; + const packageInput = (_npmRegistry || _load_npmRegistry()).default.escapeName(packageName); + var _parsePackageName = (0, (_parsePackageName2 || _load_parsePackageName()).default)(packageInput); -/** - * Reads a (potentially) variable length off the BER buffer. This call is - * not really meant to be called directly, as callers have to manipulate - * the internal buffer afterwards. - * - * As a result of this call, you can call `Reader.length`, until the - * next thing called that does a readLength. - * - * @return {Number} the amount of offset to advance the buffer. - * @throws {InvalidAsn1Error} on bad ASN.1 - */ -Reader.prototype.readLength = function (offset) { - if (offset === undefined) - offset = this._offset; + const name = _parsePackageName.name, + version = _parsePackageName.version; - if (offset >= this._size) - return null; - var lenB = this._buf[offset++] & 0xff; - if (lenB === null) - return null; + let result; + try { + result = yield config.registries.npm.request(name, { unfiltered: true }); + } catch (e) { + reporter.error(reporter.lang('infoFail')); + return; + } + if (!result) { + reporter.error(reporter.lang('infoFail')); + return; + } - if ((lenB & 0x80) === 0x80) { - lenB &= 0x7f; + result = clean(result); - if (lenB === 0) - throw newInvalidAsn1Error('Indefinite length not supported'); + const versions = result.versions; + // $FlowFixMe + result.versions = Object.keys(versions).sort(semver.compareLoose); + result.version = version || result['dist-tags'].latest; + result = Object.assign(result, versions[result.version]); - if (lenB > 4) - throw newInvalidAsn1Error('encoding too long'); + const fieldPath = args.shift(); + const fields = fieldPath ? fieldPath.split('.') : []; - if (this._size - offset < lenB) - return null; + // Readmes can be long so exclude them unless explicitly asked for. + if (fields[0] !== 'readme') { + delete result.readme; + } - this._len = 0; - for (var i = 0; i < lenB; i++) - this._len = (this._len << 8) + (this._buf[offset++] & 0xff); + result = fields.reduce(function (prev, cur) { + return prev && prev[cur]; + }, result); + reporter.inspect(result); + }); - } else { - // Wasn't a variable length - this._len = lenB; - } + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); - return offset; -}; +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; +var _npmRegistry; -/** - * Parses the next sequence in this BER buffer. - * - * To get the length of the sequence, call `Reader.length`. - * - * @return {Number} the sequence's tag. - */ -Reader.prototype.readSequence = function (tag) { - var seq = this.peek(); - if (seq === null) - return null; - if (tag !== undefined && tag !== seq) - throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + seq.toString(16)); +function _load_npmRegistry() { + return _npmRegistry = _interopRequireDefault(__webpack_require__(88)); +} - var o = this.readLength(this._offset + 1); // stored in `length` - if (o === null) - return null; +var _parsePackageName2; - this._offset = o; - return seq; -}; +function _load_parsePackageName() { + return _parsePackageName2 = _interopRequireDefault(__webpack_require__(556)); +} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -Reader.prototype.readInt = function () { - return this._readTag(ASN1.Integer); -}; +const semver = __webpack_require__(22); +function clean(object) { + if (Array.isArray(object)) { + const result = []; + object.forEach(item => { + item = clean(item); + if (item) { + result.push(item); + } + }); + return result; + } else if (typeof object === 'object') { + const result = {}; + for (const key in object) { + if (key.startsWith('_')) { + continue; + } -Reader.prototype.readBoolean = function () { - return (this._readTag(ASN1.Boolean) === 0 ? false : true); -}; + const item = clean(object[key]); + if (item) { + result[key] = item; + } + } + return result; + } else if (object) { + return object; + } else { + return null; + } +} +function setFlags(commander) { + commander.description('Shows information about a package.'); +} -Reader.prototype.readEnumeration = function () { - return this._readTag(ASN1.Enumeration); -}; +function hasWrapper(commander, args) { + return true; +} +/***/ }), +/* 502 */ +/***/ (function(module, exports, __webpack_require__) { -Reader.prototype.readString = function (tag, retbuf) { - if (!tag) - tag = ASN1.OctetString; +"use strict"; - var b = this.peek(); - if (b === null) - return null; - if (b !== tag) - throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + b.toString(16)); +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getGitConfigInfo = exports.run = exports.shouldRunInCurrentCwd = undefined; - var o = this.readLength(this._offset + 1); // stored in `length` +var _asyncToGenerator2; - if (o === null) - return null; +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} - if (this.length > this._size - o) - return null; +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const installVersion = flags[`2`] ? `berry` : flags.install; + const forwardedArgs = process.argv.slice(process.argv.indexOf('init', 2) + 1); - this._offset = o; + if (installVersion) { + if (flags[`2`] && process.env.COREPACK_ROOT) { + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [path.join(process.env.COREPACK_ROOT, 'dist/corepack.js'), `yarn@${flags.install || `stable`}`, `init`, ...forwardedArgs, `--install=self`], { + stdio: 'inherit', + cwd: config.cwd + }); + } else { + const lockfilePath = path.resolve(config.cwd, 'yarn.lock'); + if (!(yield (_fs || _load_fs()).exists(lockfilePath))) { + yield (_fs || _load_fs()).writeFile(lockfilePath, ''); + } + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [process.argv[1], 'policies', 'set-version', installVersion, '--silent'], { + stdio: 'inherit', + cwd: config.cwd + }); + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [process.argv[1], 'init', ...forwardedArgs], { + stdio: 'inherit', + cwd: config.cwd + }); + } + return; + } - if (this.length === 0) - return retbuf ? Buffer.alloc(0) : ''; + const manifests = yield config.getRootManifests(); - var str = this._buf.slice(this._offset, this._offset + this.length); - this._offset += this.length; + let repository = {}; + const author = { + name: config.getOption('init-author-name'), + email: config.getOption('init-author-email'), + url: config.getOption('init-author-url') + }; + if (yield (_fs || _load_fs()).exists(path.join(config.cwd, '.git'))) { + // get git origin of the cwd + try { + repository = { + type: 'git', + url: yield (_child || _load_child()).spawn('git', ['config', 'remote.origin.url'], { + cwd: config.cwd + }) + }; + } catch (ex) { + // Ignore - Git repo may not have an origin URL yet (eg. if it only exists locally) + } - return retbuf ? str : str.toString('utf8'); -}; + if (author.name === undefined) { + author.name = yield getGitConfigInfo('user.name'); + } -Reader.prototype.readOID = function (tag) { - if (!tag) - tag = ASN1.OID; + if (author.email === undefined) { + author.email = yield getGitConfigInfo('user.email'); + } + } - var b = this.readString(tag, true); - if (b === null) - return null; + const keys = [{ + key: 'name', + question: 'name', + default: path.basename(config.cwd), + validation: (_validate || _load_validate()).isValidPackageName, + validationError: 'invalidPackageName' + }, { + key: 'version', + question: 'version', + default: String(config.getOption('init-version')) + }, { + key: 'description', + question: 'description', + default: '' + }, { + key: 'main', + question: 'entry point', + default: 'index.js' + }, { + key: 'repository', + question: 'repository url', + default: (0, (_util || _load_util()).extractRepositoryUrl)(repository) + }, { + key: 'author', + question: 'author', + default: (0, (_util || _load_util()).stringifyPerson)(author) + }, { + key: 'license', + question: 'license', + default: String(config.getOption('init-license')) + }, { + key: 'private', + question: 'private', + default: config.getOption('init-private') || '', + inputFormatter: yn + }]; - var values = []; - var value = 0; + // get answers + const pkg = {}; + for (var _iterator = keys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref2; - for (var i = 0; i < b.length; i++) { - var byte = b[i] & 0xff; + if (_isArray) { + if (_i >= _iterator.length) break; + _ref2 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref2 = _i.value; + } - value <<= 7; - value += byte & 0x7f; - if ((byte & 0x80) === 0) { - values.push(value); - value = 0; - } - } + const entry = _ref2; + const yes = flags.yes, + privateFlag = flags.private; + const manifestKey = entry.key; + let question = entry.question, + def = entry.default; - value = values.shift(); - values.unshift(value % 40); - values.unshift((value / 40) >> 0); - return values.join('.'); -}; + for (var _iterator4 = (_index || _load_index()).registryNames, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref5; + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref5 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref5 = _i4.value; + } -Reader.prototype._readTag = function (tag) { - assert.ok(tag !== undefined); + const registryName = _ref5; + const object = manifests[registryName].object; - var b = this.peek(); + let val = objectPath.get(object, manifestKey); + if (!val) { + break; + } + if (typeof val === 'object') { + if (manifestKey === 'author') { + val = (0, (_util || _load_util()).stringifyPerson)(val); + } else if (manifestKey === 'repository') { + val = (0, (_util || _load_util()).extractRepositoryUrl)(val); + } + } + def = val; + } - if (b === null) - return null; + if (manifestKey === 'private' && privateFlag) { + def = true; + } - if (b !== tag) - throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + b.toString(16)); + if (def) { + question += ` (${String(def)})`; + } - var o = this.readLength(this._offset + 1); // stored in `length` - if (o === null) - return null; + let answer; + let validAnswer = false; - if (this.length > 4) - throw newInvalidAsn1Error('Integer too long: ' + this.length); + if (yes) { + answer = def; + } else { + // loop until a valid answer is provided, if validation is on entry + if (entry.validation) { + while (!validAnswer) { + answer = (yield reporter.question(question)) || def; + // validate answer + if (entry.validation(String(answer))) { + validAnswer = true; + } else { + reporter.error(reporter.lang('invalidPackageName')); + } + } + } else { + answer = (yield reporter.question(question)) || def; + } + } - if (this.length > this._size - o) - return null; - this._offset = o; + if (answer) { + if (entry.inputFormatter) { + answer = entry.inputFormatter(answer); + } + objectPath.set(pkg, manifestKey, answer); + } + } - var fb = this._buf[this._offset]; - var value = 0; + if (pkg.repository && (_githubResolver || _load_githubResolver()).default.isVersion(pkg.repository)) { + pkg.repository = `https://github.com/${pkg.repository}`; + } - for (var i = 0; i < this.length; i++) { - value <<= 8; - value |= (this._buf[this._offset++] & 0xff); - } + // save answers + const targetManifests = []; + for (var _iterator2 = (_index || _load_index()).registryNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref3; - if ((fb & 0x80) === 0x80 && i !== 4) - value -= (1 << (i * 8)); + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref3 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref3 = _i2.value; + } - return value >> 0; -}; + const registryName = _ref3; + const info = manifests[registryName]; + if (info.exists) { + targetManifests.push(info); + } + } + if (!targetManifests.length) { + targetManifests.push(manifests.npm); + } + for (var _iterator3 = targetManifests, _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; + } -// --- Exported API + const targetManifest = _ref4; -module.exports = Reader; + Object.assign(targetManifest.object, pkg); + reporter.success(`Saved ${path.basename(targetManifest.loc)}`); + } + yield config.saveRootManifests(manifests); + }); -/***/ }), -/* 516 */ -/***/ (function(module, exports, __webpack_require__) { + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); -// Copyright 2011 Mark Cavage All rights reserved. +let getGitConfigInfo = exports.getGitConfigInfo = (() => { + var _ref6 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (credential, spawn = (_child || _load_child()).spawn) { + try { + // try to get author default based on git config + return yield spawn('git', ['config', credential]); + } catch (e) { + return ''; + } + }); -var assert = __webpack_require__(28); -var Buffer = __webpack_require__(15).Buffer; -var ASN1 = __webpack_require__(206); -var errors = __webpack_require__(205); + return function getGitConfigInfo(_x5) { + return _ref6.apply(this, arguments); + }; +})(); +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; -// --- Globals +var _util; -var newInvalidAsn1Error = errors.newInvalidAsn1Error; +function _load_util() { + return _util = __webpack_require__(219); +} -var DEFAULT_OPTS = { - size: 1024, - growthFactor: 8 -}; +var _index; +function _load_index() { + return _index = __webpack_require__(58); +} -// --- Helpers +var _githubResolver; -function merge(from, to) { - assert.ok(from); - assert.equal(typeof (from), 'object'); - assert.ok(to); - assert.equal(typeof (to), 'object'); +function _load_githubResolver() { + return _githubResolver = _interopRequireDefault(__webpack_require__(361)); +} - var keys = Object.getOwnPropertyNames(from); - keys.forEach(function (key) { - if (to[key]) - return; +var _child; - var value = Object.getOwnPropertyDescriptor(from, key); - Object.defineProperty(to, key, value); - }); +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); +} - return to; +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); } +var _validate; +function _load_validate() { + return _validate = _interopRequireWildcard(__webpack_require__(125)); +} -// --- API +var _constants; -function Writer(options) { - options = merge(DEFAULT_OPTS, options || {}); +function _load_constants() { + return _constants = __webpack_require__(8); +} - this._buf = Buffer.alloc(options.size || 1024); - this._size = this._buf.length; - this._offset = 0; - this._options = options; +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; } } - // A list of offsets in the buffer where we need to insert - // sequence tag/len pairs. - this._seq = []; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const objectPath = __webpack_require__(304); + +const path = __webpack_require__(0); +const yn = __webpack_require__(962); + +function setFlags(commander) { + commander.description('Interactively creates or updates a package.json file.'); + commander.option('-y, --yes', 'use default options'); + commander.option('-p, --private', 'use default options and private true'); + commander.option('-i, --install ', 'install a specific Yarn release'); + commander.option('-2', 'generates the project using Yarn 2'); } -Object.defineProperty(Writer.prototype, 'buffer', { - get: function () { - if (this._seq.length) - throw newInvalidAsn1Error(this._seq.length + ' unended sequence(s)'); +function hasWrapper(commander, args) { + return true; +} - return (this._buf.slice(0, this._offset)); - } +const shouldRunInCurrentCwd = exports.shouldRunInCurrentCwd = true; + +/***/ }), +/* 503 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true }); +exports.examples = exports.run = undefined; -Writer.prototype.writeByte = function (b) { - if (typeof (b) !== 'number') - throw new TypeError('argument must be a Number'); +var _extends2; - this._ensure(1); - this._buf[this._offset++] = b; -}; +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); +} +var _asyncToGenerator2; -Writer.prototype.writeInt = function (i, tag) { - if (typeof (i) !== 'number') - throw new TypeError('argument must be a Number'); - if (typeof (tag) !== 'number') - tag = ASN1.Integer; +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} - var sz = 4; +let getManifests = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags) { + const lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.cwd); + const install = new (_install || _load_install()).Install((0, (_extends2 || _load_extends()).default)({ skipIntegrityCheck: true }, flags), config, new (_baseReporter || _load_baseReporter()).default(), lockfile); + yield install.hydrate(true); - while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && - (sz > 1)) { - sz--; - i <<= 8; - } + let manifests = install.resolver.getManifests(); - if (sz > 4) - throw newInvalidAsn1Error('BER ints cannot be > 0xffffffff'); + // sort by name + manifests = manifests.sort(function (a, b) { + if (!a.name && !b.name) { + return 0; + } - this._ensure(2 + sz); - this._buf[this._offset++] = tag; - this._buf[this._offset++] = sz; + if (!a.name) { + return 1; + } - while (sz-- > 0) { - this._buf[this._offset++] = ((i & 0xff000000) >>> 24); - i <<= 8; - } + if (!b.name) { + return -1; + } -}; + return a.name.localeCompare(b.name); + }); + // filter ignored manifests + manifests = manifests.filter(function (manifest) { + const ref = manifest._reference; + return !!ref && !ref.ignore; + }); -Writer.prototype.writeNull = function () { - this.writeByte(ASN1.Null); - this.writeByte(0x00); -}; + return manifests; + }); + return function getManifests(_x, _x2) { + return _ref.apply(this, arguments); + }; +})(); -Writer.prototype.writeEnumeration = function (i, tag) { - if (typeof (i) !== 'number') - throw new TypeError('argument must be a Number'); - if (typeof (tag) !== 'number') - tag = ASN1.Enumeration; +let list = (() => { + var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const manifests = yield getManifests(config, flags); + const manifestsByLicense = new Map(); - return this.writeInt(i, tag); -}; + for (var _iterator = manifests, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref4; + if (_isArray) { + if (_i >= _iterator.length) break; + _ref4 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref4 = _i.value; + } -Writer.prototype.writeBoolean = function (b, tag) { - if (typeof (b) !== 'boolean') - throw new TypeError('argument must be a Boolean'); - if (typeof (tag) !== 'number') - tag = ASN1.Boolean; + const _ref3 = _ref4; + const name = _ref3.name, + version = _ref3.version, + license = _ref3.license, + repository = _ref3.repository, + homepage = _ref3.homepage, + author = _ref3.author; - this._ensure(3); - this._buf[this._offset++] = tag; - this._buf[this._offset++] = 0x01; - this._buf[this._offset++] = b ? 0xff : 0x00; -}; + const licenseKey = license || 'UNKNOWN'; + const url = repository ? repository.url : homepage; + const vendorUrl = homepage || author && author.url; + const vendorName = author && author.name; + if (!manifestsByLicense.has(licenseKey)) { + manifestsByLicense.set(licenseKey, new Map()); + } -Writer.prototype.writeString = function (s, tag) { - if (typeof (s) !== 'string') - throw new TypeError('argument must be a string (was: ' + typeof (s) + ')'); - if (typeof (tag) !== 'number') - tag = ASN1.OctetString; + const byLicense = manifestsByLicense.get(licenseKey); + invariant(byLicense, 'expected value'); + byLicense.set(`${name}@${version}`, { + name, + version, + url, + vendorUrl, + vendorName + }); + } - var len = Buffer.byteLength(s); - this.writeByte(tag); - this.writeLength(len); - if (len) { - this._ensure(len); - this._buf.write(s, this._offset); - this._offset += len; - } -}; + if (flags.json) { + const body = []; + manifestsByLicense.forEach(function (license, licenseKey) { + license.forEach(function ({ name, version, url, vendorUrl, vendorName }) { + body.push([name, version, licenseKey, url || 'Unknown', vendorUrl || 'Unknown', vendorName || 'Unknown']); + }); + }); -Writer.prototype.writeBuffer = function (buf, tag) { - if (typeof (tag) !== 'number') - throw new TypeError('tag must be a number'); - if (!Buffer.isBuffer(buf)) - throw new TypeError('argument must be a buffer'); + reporter.table(['Name', 'Version', 'License', 'URL', 'VendorUrl', 'VendorName'], body); + } else { + const trees = []; - this.writeByte(tag); - this.writeLength(buf.length); - this._ensure(buf.length); - buf.copy(this._buf, this._offset, 0, buf.length); - this._offset += buf.length; -}; + manifestsByLicense.forEach(function (license, licenseKey) { + const licenseTree = []; + license.forEach(function ({ name, version, url, vendorUrl, vendorName }) { + const children = []; -Writer.prototype.writeStringArray = function (strings) { - if ((!strings instanceof Array)) - throw new TypeError('argument must be an Array[String]'); + if (url) { + children.push({ name: `${reporter.format.bold('URL:')} ${url}` }); + } - var self = this; - strings.forEach(function (s) { - self.writeString(s); - }); -}; + if (vendorUrl) { + children.push({ name: `${reporter.format.bold('VendorUrl:')} ${vendorUrl}` }); + } -// This is really to solve DER cases, but whatever for now -Writer.prototype.writeOID = function (s, tag) { - if (typeof (s) !== 'string') - throw new TypeError('argument must be a string'); - if (typeof (tag) !== 'number') - tag = ASN1.OID; + if (vendorName) { + children.push({ name: `${reporter.format.bold('VendorName:')} ${vendorName}` }); + } - if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) - throw new Error('argument is not a valid OID string'); + licenseTree.push({ + name: `${name}@${version}`, + children + }); + }); - function encodeOctet(bytes, octet) { - if (octet < 128) { - bytes.push(octet); - } else if (octet < 16384) { - bytes.push((octet >>> 7) | 0x80); - bytes.push(octet & 0x7F); - } else if (octet < 2097152) { - bytes.push((octet >>> 14) | 0x80); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } else if (octet < 268435456) { - bytes.push((octet >>> 21) | 0x80); - bytes.push(((octet >>> 14) | 0x80) & 0xFF); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } else { - bytes.push(((octet >>> 28) | 0x80) & 0xFF); - bytes.push(((octet >>> 21) | 0x80) & 0xFF); - bytes.push(((octet >>> 14) | 0x80) & 0xFF); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } - } + trees.push({ + name: licenseKey, + children: licenseTree + }); + }); - var tmp = s.split('.'); - var bytes = []; - bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); - tmp.slice(2).forEach(function (b) { - encodeOctet(bytes, parseInt(b, 10)); + reporter.tree('licenses', trees, { force: true }); + } }); - var self = this; - this._ensure(2 + bytes.length); - this.writeByte(tag); - this.writeLength(bytes.length); - bytes.forEach(function (b) { - self.writeByte(b); - }); -}; + return function list(_x3, _x4, _x5, _x6) { + return _ref2.apply(this, arguments); + }; +})(); +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; -Writer.prototype.writeLength = function (len) { - if (typeof (len) !== 'number') - throw new TypeError('argument must be a Number'); +var _baseReporter; - this._ensure(4); +function _load_baseReporter() { + return _baseReporter = _interopRequireDefault(__webpack_require__(108)); +} - if (len <= 0x7f) { - this._buf[this._offset++] = len; - } else if (len <= 0xff) { - this._buf[this._offset++] = 0x81; - this._buf[this._offset++] = len; - } else if (len <= 0xffff) { - this._buf[this._offset++] = 0x82; - this._buf[this._offset++] = len >> 8; - this._buf[this._offset++] = len; - } else if (len <= 0xffffff) { - this._buf[this._offset++] = 0x83; - this._buf[this._offset++] = len >> 16; - this._buf[this._offset++] = len >> 8; - this._buf[this._offset++] = len; - } else { - throw newInvalidAsn1Error('Length too long (> 4 bytes)'); - } -}; +var _install; -Writer.prototype.startSequence = function (tag) { - if (typeof (tag) !== 'number') - tag = ASN1.Sequence | ASN1.Constructor; +function _load_install() { + return _install = __webpack_require__(34); +} - this.writeByte(tag); - this._seq.push(this._offset); - this._ensure(3); - this._offset += 3; -}; +var _lockfile; +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); +} -Writer.prototype.endSequence = function () { - var seq = this._seq.pop(); - var start = seq + 3; - var len = this._offset - start; +var _buildSubCommands2; - if (len <= 0x7f) { - this._shift(start, len, -2); - this._buf[seq] = len; - } else if (len <= 0xff) { - this._shift(start, len, -1); - this._buf[seq] = 0x81; - this._buf[seq + 1] = len; - } else if (len <= 0xffff) { - this._buf[seq] = 0x82; - this._buf[seq + 1] = len >> 8; - this._buf[seq + 2] = len; - } else if (len <= 0xffffff) { - this._shift(start, len, 1); - this._buf[seq] = 0x83; - this._buf[seq + 1] = len >> 16; - this._buf[seq + 2] = len >> 8; - this._buf[seq + 3] = len; - } else { - throw newInvalidAsn1Error('Sequence too long'); - } -}; +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); +} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -Writer.prototype._shift = function (start, len, shift) { - assert.ok(start !== undefined); - assert.ok(len !== undefined); - assert.ok(shift); +const invariant = __webpack_require__(9); - this._buf.copy(this._buf, start + shift, start, start + len); - this._offset += shift; -}; +function hasWrapper(flags, args) { + return args[0] != 'generate-disclaimer'; +} -Writer.prototype._ensure = function (len) { - assert.ok(len); +function setFlags(commander) { + commander.description('Lists licenses for installed packages.'); +} - if (this._size - this._offset < len) { - var sz = this._size * this._options.growthFactor; - if (sz - this._offset < len) - sz += len; +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('licenses', { + ls(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + reporter.warn(`\`yarn licenses ls\` is deprecated. Please use \`yarn licenses list\`.`); + yield list(config, reporter, flags, args); + })(); + }, - var buf = Buffer.alloc(sz); + list(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + yield list(config, reporter, flags, args); + })(); + }, - this._buf.copy(buf, 0, 0, this._offset); - this._buf = buf; - this._size = sz; - } -}; + generateDisclaimer(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + /* eslint-disable no-console */ + // `reporter.log` dumps a bunch of ANSI escapes to clear the current line and + // is for abstracting the console output so it can be consumed by other tools + // (JSON output being the primary one). This command is only for text consumption + // and you should just be dumping it to a TXT file. Using a reporter here has the + // potential to mess up the output since it might print ansi escapes. + const manifests = yield getManifests(config, flags); + const manifest = yield config.readRootManifest(); + // Create a map of license text to manifest so that packages with exactly + // the same license text are grouped together. + const manifestsByLicense = new Map(); + for (var _iterator2 = manifests, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref5; -// --- Exported API + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref5 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref5 = _i2.value; + } -module.exports = Writer; + const manifest = _ref5; + const licenseText = manifest.licenseText, + noticeText = manifest.noticeText; + let licenseKey; + if (!licenseText) { + continue; + } -/***/ }), -/* 517 */ -/***/ (function(module, exports, __webpack_require__) { + if (!noticeText) { + licenseKey = licenseText; + } else { + licenseKey = `${licenseText}\n\nNOTICE\n\n${noticeText}`; + } -module.exports = -{ - parallel : __webpack_require__(519), - serial : __webpack_require__(520), - serialOrdered : __webpack_require__(351) -}; + if (!manifestsByLicense.has(licenseKey)) { + manifestsByLicense.set(licenseKey, new Map()); + } + const byLicense = manifestsByLicense.get(licenseKey); + invariant(byLicense, 'expected value'); + byLicense.set(manifest.name, manifest); + } -/***/ }), -/* 518 */ -/***/ (function(module, exports) { + console.log('THE FOLLOWING SETS FORTH ATTRIBUTION NOTICES FOR THIRD PARTY SOFTWARE THAT MAY BE CONTAINED ' + `IN PORTIONS OF THE ${String(manifest.name).toUpperCase().replace(/-/g, ' ')} PRODUCT.`); + console.log(); -module.exports = defer; + for (var _iterator3 = manifestsByLicense, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref7; -/** - * Runs provided function on next iteration of the event loop - * - * @param {function} fn - function to run - */ -function defer(fn) -{ - var nextTick = typeof setImmediate == 'function' - ? setImmediate - : ( - typeof process == 'object' && typeof process.nextTick == 'function' - ? process.nextTick - : null - ); + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref7 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref7 = _i3.value; + } - if (nextTick) - { - nextTick(fn); - } - else - { - setTimeout(fn, 0); - } -} + const _ref6 = _ref7; + const licenseKey = _ref6[0]; + const manifests = _ref6[1]; + console.log('-----'); + console.log(); -/***/ }), -/* 519 */ -/***/ (function(module, exports, __webpack_require__) { + const names = []; + const urls = []; + for (var _iterator4 = manifests, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref9; -var iterate = __webpack_require__(348) - , initState = __webpack_require__(349) - , terminator = __webpack_require__(350) - ; + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref9 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref9 = _i4.value; + } -// Public API -module.exports = parallel; + const _ref8 = _ref9; + const name = _ref8[0]; + const repository = _ref8[1].repository; -/** - * Runs iterator over provided array elements in parallel - * - * @param {array|object} list - array or object (named list) to iterate over - * @param {function} iterator - iterator to run - * @param {function} callback - invoked when all elements processed - * @returns {function} - jobs terminator - */ -function parallel(list, iterator, callback) -{ - var state = initState(list); + names.push(name); + if (repository && repository.url) { + urls.push(manifests.size === 1 ? repository.url : `${repository.url} (${name})`); + } + } - while (state.index < (state['keyedList'] || list).length) - { - iterate(list, iterator, state, function(error, result) - { - if (error) - { - callback(error, result); - return; - } + const heading = []; + heading.push(`The following software may be included in this product: ${names.join(', ')}.`); + if (urls.length > 0) { + heading.push(`A copy of the source code may be downloaded from ${urls.join(', ')}.`); + } + heading.push('This software contains the following license and notice below:'); - // looks like it's the last one - if (Object.keys(state.jobs).length === 0) - { - callback(null, state.results); - return; - } - }); + console.log(heading.join(' ')); + console.log(); - state.index++; - } + if (licenseKey) { + console.log(licenseKey.trim()); + } else { + // what do we do here? base it on `license`? + } - return terminator.bind(state, callback); -} + console.log(); + } + })(); + } +}); +const run = _buildSubCommands.run, + examples = _buildSubCommands.examples; +exports.run = run; +exports.examples = examples; /***/ }), -/* 520 */ +/* 504 */ /***/ (function(module, exports, __webpack_require__) { -var serialOrdered = __webpack_require__(351); +"use strict"; -// Public API -module.exports = serial; -/** - * Runs iterator over provided array elements in series - * - * @param {array|object} list - array or object (named list) to iterate over - * @param {function} iterator - iterator to run - * @param {function} callback - invoked when all elements processed - * @returns {function} - jobs terminator - */ -function serial(list, iterator, callback) -{ - return serialOrdered(list, iterator, null, callback); +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + yield config.registries.yarn.saveHomeConfig({ + username: undefined, + email: undefined + }); -/***/ }), -/* 521 */ -/***/ (function(module, exports, __webpack_require__) { + reporter.success(reporter.lang('clearedCredentials')); + }); + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); -/*! - * Copyright 2010 LearnBoost - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; -/** - * Module dependencies. - */ +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var crypto = __webpack_require__(11) - , parse = __webpack_require__(24).parse - ; +function setFlags(commander) { + commander.description('Clears registry username and email.'); +} -/** - * Valid keys. - */ +function hasWrapper(commander, args) { + return true; +} -var keys = - [ 'acl' - , 'location' - , 'logging' - , 'notification' - , 'partNumber' - , 'policy' - , 'requestPayment' - , 'torrent' - , 'uploadId' - , 'uploads' - , 'versionId' - , 'versioning' - , 'versions' - , 'website' - ] +/***/ }), +/* 505 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Return an "Authorization" header value with the given `options` - * in the form of "AWS :" - * - * @param {Object} options - * @return {String} - * @api private - */ +"use strict"; -function authorization (options) { - return 'AWS ' + options.key + ':' + sign(options) -} -module.exports = authorization -module.exports.authorization = authorization +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = undefined; -/** - * Simple HMAC-SHA1 Wrapper - * - * @param {Object} options - * @return {String} - * @api private - */ +var _extends2; -function hmacSha1 (options) { - return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64') +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } -module.exports.hmacSha1 = hmacSha1 - -/** - * Create a base64 sha1 HMAC for `options`. - * - * @param {Object} options - * @return {String} - * @api private - */ +var _asyncToGenerator2; -function sign (options) { - options.message = stringToSign(options) - return hmacSha1(options) +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -module.exports.sign = sign -/** - * Create a base64 sha1 HMAC for `options`. - * - * Specifically to be used with S3 presigned URLs - * - * @param {Object} options - * @return {String} - * @api private - */ - -function signQuery (options) { - options.message = queryStringToSign(options) - return hmacSha1(options) -} -module.exports.signQuery= signQuery +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const pnpPath = `${config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; -/** - * Return a string for sign() with the given `options`. - * - * Spec: - * - * \n - * \n - * \n - * \n - * [headers\n] - * - * - * @param {Object} options - * @return {String} - * @api private - */ + let nodeOptions = process.env.NODE_OPTIONS || ''; + if (yield (_fs || _load_fs()).exists(pnpPath)) { + nodeOptions = `--require ${pnpPath} ${nodeOptions}`; + } -function stringToSign (options) { - var headers = options.amazonHeaders || '' - if (headers) headers += '\n' - var r = - [ options.verb - , options.md5 - , options.contentType - , options.date ? options.date.toUTCString() : '' - , headers + options.resource - ] - return r.join('\n') -} -module.exports.stringToSign = stringToSign + try { + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, args, { + stdio: 'inherit', + cwd: flags.into || config.cwd, + env: (0, (_extends2 || _load_extends()).default)({}, process.env, { NODE_OPTIONS: nodeOptions }) + }); + } catch (err) { + throw err; + } + }); -/** - * Return a string for sign() with the given `options`, but is meant exclusively - * for S3 presigned URLs - * - * Spec: - * - * \n - * - * - * @param {Object} options - * @return {String} - * @api private - */ + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); -function queryStringToSign (options){ - return 'GET\n\n\n' + options.date + '\n' + options.resource -} -module.exports.queryStringToSign = queryStringToSign +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; -/** - * Perform the following: - * - * - ignore non-amazon headers - * - lowercase fields - * - sort lexicographically - * - trim whitespace between ":" - * - join with newline - * - * @param {Object} headers - * @return {String} - * @api private - */ +var _child; -function canonicalizeHeaders (headers) { - var buf = [] - , fields = Object.keys(headers) - ; - for (var i = 0, len = fields.length; i < len; ++i) { - var field = fields[i] - , val = headers[field] - , field = field.toLowerCase() - ; - if (0 !== field.indexOf('x-amz')) continue - buf.push(field + ':' + val) - } - return buf.sort().join('\n') +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); } -module.exports.canonicalizeHeaders = canonicalizeHeaders - -/** - * Perform the following: - * - * - ignore non sub-resources - * - sort lexicographically - * - * @param {String} resource - * @return {String} - * @api private - */ - -function canonicalizeResource (resource) { - var url = parse(resource, true) - , path = url.pathname - , buf = [] - ; - Object.keys(url.query).forEach(function(key){ - if (!~keys.indexOf(key)) return - var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]) - buf.push(key + val) - }) +var _fs; - return path + (buf.length ? '?' + buf.sort().join('&') : '') +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); } -module.exports.canonicalizeResource = canonicalizeResource - -/***/ }), -/* 522 */ -/***/ (function(module, exports, __webpack_require__) { +var _constants; -var aws4 = exports, - url = __webpack_require__(24), - querystring = __webpack_require__(196), - crypto = __webpack_require__(11), - lru = __webpack_require__(523), - credentialsCache = lru(1000) +function _load_constants() { + return _constants = __webpack_require__(8); +} -// http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html +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 hmac(key, string, encoding) { - return crypto.createHmac('sha256', key).update(string, 'utf8').digest(encoding) -} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function hash(string, encoding) { - return crypto.createHash('sha256').update(string, 'utf8').digest(encoding) +function setFlags(commander) { + commander.description('Runs Node with the same version that the one used by Yarn itself, and by default from the project root'); + commander.usage('node [--into PATH] [... args]'); + commander.option('--into ', 'Sets the cwd to the specified location'); } -// This function assumes the string has already been percent encoded -function encodeRfc3986(urlEncodedString) { - return urlEncodedString.replace(/[!'()*]/g, function(c) { - return '%' + c.charCodeAt(0).toString(16).toUpperCase() - }) +function hasWrapper(commander, args) { + return true; } -// request: { path | body, [host], [method], [headers], [service], [region] } -// credentials: { accessKeyId, secretAccessKey, [sessionToken] } -function RequestSigner(request, credentials) { - - if (typeof request === 'string') request = url.parse(request) - - var headers = request.headers = (request.headers || {}), - hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host) - - this.request = request - this.credentials = credentials || this.defaultCredentials() - - this.service = request.service || hostParts[0] || '' - this.region = request.region || hostParts[1] || 'us-east-1' - - // SES uses a different domain from the service name - if (this.service === 'email') this.service = 'ses' - - if (!request.method && request.body) - request.method = 'POST' - - if (!headers.Host && !headers.host) { - headers.Host = request.hostname || request.host || this.createHost() +/***/ }), +/* 506 */ +/***/ (function(module, exports, __webpack_require__) { - // If a port is specified explicitly, use it as is - if (request.port) - headers.Host += ':' + request.port - } - if (!request.hostname && !request.host) - request.hostname = headers.Host || headers.host +"use strict"; - this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT' -} -RequestSigner.prototype.matchHost = function(host) { - var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com$/) - var hostParts = (match || []).slice(1, 3) +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = exports.requireLockfile = undefined; - // ES's hostParts are sometimes the other way round, if the value that is expected - // to be region equals ‘es’ switch them back - // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com - if (hostParts[1] === 'es') - hostParts = hostParts.reverse() +var _extends2; - return hostParts +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } -// http://docs.aws.amazon.com/general/latest/gr/rande.html -RequestSigner.prototype.isSingleRegion = function() { - // Special case for S3 and SimpleDB in us-east-1 - if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true - - return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'] - .indexOf(this.service) >= 0 -} +var _asyncToGenerator2; -RequestSigner.prototype.createHost = function() { - var region = this.isSingleRegion() ? '' : - (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region, - service = this.service === 'ses' ? 'email' : this.service - return service + region + '.amazonaws.com' +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -RequestSigner.prototype.prepareRequest = function() { - this.parsePath() - - var request = this.request, headers = request.headers, query +let run = exports.run = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder); + const install = new (_install || _load_install()).Install((0, (_extends2 || _load_extends()).default)({}, flags, { includeWorkspaceDeps: true }), config, reporter, lockfile); + let deps = yield (_packageRequest || _load_packageRequest()).default.getOutdatedPackages(lockfile, install, config, reporter); - if (request.signQuery) { + if (args.length) { + const requested = new Set(args); - this.parsedPath.query = query = this.parsedPath.query || {} + deps = deps.filter(function ({ name }) { + return requested.has(name); + }); + } - if (this.credentials.sessionToken) - query['X-Amz-Security-Token'] = this.credentials.sessionToken + const getNameFromHint = function getNameFromHint(hint) { + return hint ? `${hint}Dependencies` : 'dependencies'; + }; + const colorizeName = function colorizeName({ current, latest, name }) { + return reporter.format[(0, (_colorForVersions || _load_colorForVersions()).default)(current, latest)](name); + }; - if (this.service === 's3' && !query['X-Amz-Expires']) - query['X-Amz-Expires'] = 86400 + if (deps.length) { + const usesWorkspaces = !!config.workspaceRootFolder; + const body = deps.map(function (info) { + const row = [colorizeName(info), info.current, (0, (_colorizeDiff || _load_colorizeDiff()).default)(info.current, info.wanted, reporter), reporter.format.cyan(info.latest), info.workspaceName || '', getNameFromHint(info.hint), reporter.format.cyan(info.url)]; + if (!usesWorkspaces) { + row.splice(4, 1); + } + return row; + }); - if (query['X-Amz-Date']) - this.datetime = query['X-Amz-Date'] - else - query['X-Amz-Date'] = this.getDateTime() + const red = reporter.format.red(''); + const yellow = reporter.format.yellow(''); + const green = reporter.format.green(''); + reporter.info(reporter.lang('legendColorsForVersionUpdates', red, yellow, green)); - query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256' - query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString() - query['X-Amz-SignedHeaders'] = this.signedHeaders() + const header = ['Package', 'Current', 'Wanted', 'Latest', 'Workspace', 'Package Type', 'URL']; + if (!usesWorkspaces) { + header.splice(4, 1); + } + reporter.table(header, body); - } else { + return 1; + } + return 0; + }); - if (!request.doNotModifyHeaders && !this.isCodeCommitGit) { - if (request.body && !headers['Content-Type'] && !headers['content-type']) - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8' + return function run(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); - if (request.body && !headers['Content-Length'] && !headers['content-length']) - headers['Content-Length'] = Buffer.byteLength(request.body) +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; - if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token']) - headers['X-Amz-Security-Token'] = this.credentials.sessionToken +var _packageRequest; - if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256']) - headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex') +function _load_packageRequest() { + return _packageRequest = _interopRequireDefault(__webpack_require__(122)); +} - if (headers['X-Amz-Date'] || headers['x-amz-date']) - this.datetime = headers['X-Amz-Date'] || headers['x-amz-date'] - else - headers['X-Amz-Date'] = this.getDateTime() - } +var _lockfile; - delete headers.Authorization - delete headers.authorization - } +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); } -RequestSigner.prototype.sign = function() { - if (!this.parsedPath) this.prepareRequest() +var _install; - if (this.request.signQuery) { - this.parsedPath.query['X-Amz-Signature'] = this.signature() - } else { - this.request.headers.Authorization = this.authHeader() - } +function _load_install() { + return _install = __webpack_require__(34); +} - this.request.path = this.formatPath() +var _colorForVersions; - return this.request +function _load_colorForVersions() { + return _colorForVersions = _interopRequireDefault(__webpack_require__(363)); } -RequestSigner.prototype.getDateTime = function() { - if (!this.datetime) { - var headers = this.request.headers, - date = new Date(headers.Date || headers.date || new Date) - - this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '') +var _colorizeDiff; - // Remove the trailing 'Z' on the timestamp string for CodeCommit git access - if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1) - } - return this.datetime +function _load_colorizeDiff() { + return _colorizeDiff = _interopRequireDefault(__webpack_require__(364)); } -RequestSigner.prototype.getDate = function() { - return this.getDateTime().substr(0, 8) -} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -RequestSigner.prototype.authHeader = function() { - return [ - 'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), - 'SignedHeaders=' + this.signedHeaders(), - 'Signature=' + this.signature(), - ].join(', ') -} +const requireLockfile = exports.requireLockfile = true; -RequestSigner.prototype.signature = function() { - var date = this.getDate(), - cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(), - kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey) - if (!kCredentials) { - kDate = hmac('AWS4' + this.credentials.secretAccessKey, date) - kRegion = hmac(kDate, this.region) - kService = hmac(kRegion, this.service) - kCredentials = hmac(kService, 'aws4_request') - credentialsCache.set(cacheKey, kCredentials) - } - return hmac(kCredentials, this.stringToSign(), 'hex') +function setFlags(commander) { + commander.description('Checks for outdated package dependencies.'); + commander.usage('outdated [packages ...]'); } -RequestSigner.prototype.stringToSign = function() { - return [ - 'AWS4-HMAC-SHA256', - this.getDateTime(), - this.credentialString(), - hash(this.canonicalString(), 'hex'), - ].join('\n') +function hasWrapper(commander, args) { + return true; } -RequestSigner.prototype.canonicalString = function() { - if (!this.parsedPath) this.prepareRequest() - - var pathStr = this.parsedPath.path, - query = this.parsedPath.query, - headers = this.request.headers, - queryStr = '', - normalizePath = this.service !== 's3', - decodePath = this.service === 's3' || this.request.doNotEncodePath, - decodeSlashesInPath = this.service === 's3', - firstValOnly = this.service === 's3', - bodyHash +/***/ }), +/* 507 */ +/***/ (function(module, exports, __webpack_require__) { - if (this.service === 's3' && this.request.signQuery) { - bodyHash = 'UNSIGNED-PAYLOAD' - } else if (this.isCodeCommitGit) { - bodyHash = '' - } else { - bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] || - hash(this.request.body || '', 'hex') - } +"use strict"; - if (query) { - queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function(obj, key) { - if (!key) return obj - obj[key] = !Array.isArray(query[key]) ? query[key] : - (firstValOnly ? query[key][0] : query[key].slice().sort()) - return obj - }, {}))) - } - if (pathStr !== '/') { - if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/') - pathStr = pathStr.split('/').reduce(function(path, piece) { - if (normalizePath && piece === '..') { - path.pop() - } else if (!normalizePath || piece !== '.') { - if (decodePath) piece = decodeURIComponent(piece) - path.push(encodeRfc3986(encodeURIComponent(piece))) - } - return path - }, []).join('/') - if (pathStr[0] !== '/') pathStr = '/' + pathStr - if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/') - } - return [ - this.request.method || 'GET', - pathStr, - queryStr, - this.canonicalHeaders() + '\n', - this.signedHeaders(), - bodyHash, - ].join('\n') -} +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.examples = exports.hasWrapper = exports.run = exports.mutate = undefined; -RequestSigner.prototype.canonicalHeaders = function() { - var headers = this.request.headers - function trimAll(header) { - return header.toString().trim().replace(/\s+/g, ' ') - } - return Object.keys(headers) - .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 }) - .map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) }) - .join('\n') -} +var _asyncToGenerator2; -RequestSigner.prototype.signedHeaders = function() { - return Object.keys(this.request.headers) - .map(function(key) { return key.toLowerCase() }) - .sort() - .join(';') +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -RequestSigner.prototype.credentialString = function() { - return [ - this.getDate(), - this.region, - this.service, - 'aws4_request', - ].join('/') -} +let mutate = exports.mutate = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (args, config, reporter, buildMessages, mutator) { + if (args.length !== 2 && args.length !== 1) { + return false; + } -RequestSigner.prototype.defaultCredentials = function() { - var env = process.env - return { - accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, - secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, - sessionToken: env.AWS_SESSION_TOKEN, - } -} + const username = args.shift(); + const name = yield (0, (_tag || _load_tag()).getName)(args, config); + if (!(0, (_validate || _load_validate()).isValidPackageName)(name)) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('invalidPackageName')); + } -RequestSigner.prototype.parsePath = function() { - var path = this.request.path || '/', - queryIx = path.indexOf('?'), - query = null + const msgs = buildMessages(username, name); + reporter.step(1, 3, reporter.lang('loggingIn')); + const revoke = yield (0, (_login || _load_login()).getToken)(config, reporter, name); - if (queryIx >= 0) { - query = querystring.parse(path.slice(queryIx + 1)) - path = path.slice(0, queryIx) - } + reporter.step(2, 3, msgs.info); + const user = yield config.registries.npm.request(`-/user/org.couchdb.user:${username}`); + let error = false; + if (user) { + // get package + const pkg = yield config.registries.npm.request((_npmRegistry || _load_npmRegistry()).default.escapeName(name)); + if (pkg) { + pkg.maintainers = pkg.maintainers || []; + error = mutator({ name: user.name, email: user.email }, pkg); + } else { + error = true; + reporter.error(reporter.lang('unknownPackage', name)); + } - // S3 doesn't always encode characters > 127 correctly and - // all services don't encode characters > 255 correctly - // So if there are non-reserved chars (and it's not already all % encoded), just encode them all - if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) { - path = path.split('/').map(function(piece) { - return encodeURIComponent(decodeURIComponent(piece)) - }).join('/') - } + // update package + if (pkg && !error) { + const res = yield config.registries.npm.request(`${(_npmRegistry || _load_npmRegistry()).default.escapeName(name)}/-rev/${pkg._rev}`, { + method: 'PUT', + body: { + _id: pkg._id, + _rev: pkg._rev, + maintainers: pkg.maintainers + } + }); - this.parsedPath = { - path: path, - query: query, - } -} + if (res != null && res.success) { + reporter.success(msgs.success); + } else { + error = true; + reporter.error(msgs.error); + } + } + } else { + error = true; + reporter.error(reporter.lang('unknownUser', username)); + } -RequestSigner.prototype.formatPath = function() { - var path = this.parsedPath.path, - query = this.parsedPath.query + reporter.step(3, 3, reporter.lang('revokingToken')); + yield revoke(); - if (!query) return path + if (error) { + throw new Error(); + } else { + return true; + } + }); - // Services don't support empty query string keys - if (query[''] != null) delete query[''] + return function mutate(_x, _x2, _x3, _x4, _x5) { + return _ref.apply(this, arguments); + }; +})(); - return path + '?' + encodeRfc3986(querystring.stringify(query)) -} +let list = (() => { + var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + if (args.length > 1) { + return false; + } + const name = yield (0, (_tag || _load_tag()).getName)(args, config); + reporter.step(1, 1, reporter.lang('ownerGetting', name)); + const pkg = yield config.registries.npm.request(name, { unfiltered: true }); + if (pkg) { + const owners = pkg.maintainers; + if (!owners || !owners.length) { + reporter.warn(reporter.lang('ownerNone')); + } else { + for (var _iterator = owners, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref3; -aws4.RequestSigner = RequestSigner + if (_isArray) { + if (_i >= _iterator.length) break; + _ref3 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref3 = _i.value; + } -aws4.sign = function(request, credentials) { - return new RequestSigner(request, credentials).sign() -} + const owner = _ref3; + reporter.info(`${owner.name} <${owner.email}>`); + } + } + } else { + reporter.error(reporter.lang('ownerGettingFailed')); + } -/***/ }), -/* 523 */ -/***/ (function(module, exports) { + if (pkg) { + return true; + } else { + throw new Error(); + } + }); -module.exports = function(size) { - return new LruCache(size) -} + return function list(_x6, _x7, _x8, _x9) { + return _ref2.apply(this, arguments); + }; +})(); -function LruCache(size) { - this.capacity = size | 0 - this.map = Object.create(null) - this.list = new DoublyLinkedList() -} +exports.setFlags = setFlags; -LruCache.prototype.get = function(key) { - var node = this.map[key] - if (node == null) return undefined - this.used(node) - return node.val -} +var _errors; -LruCache.prototype.set = function(key, val) { - var node = this.map[key] - if (node != null) { - node.val = val - } else { - if (!this.capacity) this.prune() - if (!this.capacity) return false - node = new DoublyLinkedNode(key, val) - this.map[key] = node - this.capacity-- - } - this.used(node) - return true +function _load_errors() { + return _errors = __webpack_require__(6); } -LruCache.prototype.used = function(node) { - this.list.moveToFront(node) -} +var _buildSubCommands2; -LruCache.prototype.prune = function() { - var node = this.list.pop() - if (node != null) { - delete this.map[node.key] - this.capacity++ - } +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); } +var _validate; -function DoublyLinkedList() { - this.firstNode = null - this.lastNode = null +function _load_validate() { + return _validate = __webpack_require__(125); } -DoublyLinkedList.prototype.moveToFront = function(node) { - if (this.firstNode == node) return - - this.remove(node) +var _tag; - if (this.firstNode == null) { - this.firstNode = node - this.lastNode = node - node.prev = null - node.next = null - } else { - node.prev = null - node.next = this.firstNode - node.next.prev = node - this.firstNode = node - } +function _load_tag() { + return _tag = __webpack_require__(355); } -DoublyLinkedList.prototype.pop = function() { - var lastNode = this.lastNode - if (lastNode != null) { - this.remove(lastNode) - } - return lastNode -} +var _login; -DoublyLinkedList.prototype.remove = function(node) { - if (this.firstNode == node) { - this.firstNode = node.next - } else if (node.prev != null) { - node.prev.next = node.next - } - if (this.lastNode == node) { - this.lastNode = node.prev - } else if (node.next != null) { - node.next.prev = node.prev - } +function _load_login() { + return _login = __webpack_require__(107); } +var _npmRegistry; -function DoublyLinkedNode(key, val) { - this.key = key - this.val = val - this.prev = null - this.next = null +function _load_npmRegistry() { + return _npmRegistry = _interopRequireDefault(__webpack_require__(88)); } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/***/ }), -/* 524 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - +function remove(config, reporter, flags, args) { + return mutate(args, config, reporter, (username, name) => ({ + info: reporter.lang('ownerRemoving', username, name), + success: reporter.lang('ownerRemoved'), + error: reporter.lang('ownerRemoveError') + }), (user, pkg) => { + let found = false; -Object.defineProperty(exports, "__esModule", { - value: true -}); + pkg.maintainers = pkg.maintainers.filter(o => { + const match = o.name === user.name; + found = found || match; + return !match; + }); -exports.default = function (message) { - return { - useless: true, - run() { - throw new (_errors || _load_errors()).MessageError(message); - }, - setFlags: () => {}, - hasWrapper: () => true - }; -}; + if (!found) { + reporter.error(reporter.lang('userNotAnOwner', user.name)); + } -var _errors; + return found; + }); +} -function _load_errors() { - return _errors = __webpack_require__(6); +function setFlags(commander) { + commander.description('Manages package owners.'); } -/***/ }), -/* 525 */ -/***/ (function(module, exports, __webpack_require__) { +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('owner', { + add(config, reporter, flags, args) { + return mutate(args, config, reporter, (username, name) => ({ + info: reporter.lang('ownerAdding', username, name), + success: reporter.lang('ownerAdded'), + error: reporter.lang('ownerAddingFailed') + }), (user, pkg) => { + for (var _iterator2 = pkg.maintainers, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref4; -"use strict"; + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref4 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref4 = _i2.value; + } + const owner = _ref4; -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.examples = exports.hasWrapper = exports.run = undefined; -exports.setFlags = setFlags; + if (owner.name === user) { + reporter.error(reporter.lang('ownerAlready')); + return true; + } + } -var _buildSubCommands2; + pkg.maintainers.push(user); -function _load_buildSubCommands() { - return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); -} + return false; + }); + }, -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + rm(config, reporter, flags, args) { + reporter.warn(`\`yarn owner rm\` is deprecated. Please use \`yarn owner remove\`.`); + return remove(config, reporter, flags, args); + }, -const notYetImplemented = () => Promise.reject(new Error('This command is not implemented yet.')); + remove(config, reporter, flags, args) { + return remove(config, reporter, flags, args); + }, -function setFlags(commander) { - commander.description('Has not been implemented yet'); -} + ls(config, reporter, flags, args) { + reporter.warn(`\`yarn owner ls\` is deprecated. Please use \`yarn owner list\`.`); + return list(config, reporter, flags, args); + }, -var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('access', { - public: notYetImplemented, - restricted: notYetImplemented, - grant: notYetImplemented, - revoke: notYetImplemented, - lsPackages: notYetImplemented, - lsCollaborators: notYetImplemented, - edit: notYetImplemented -}, ['WARNING: This command yet to be implemented.', 'public []', 'restricted []', 'grant []', 'revoke []', 'ls-packages [||]', 'ls-collaborators [ []]', 'edit []']); + list(config, reporter, flags, args) { + return list(config, reporter, flags, args); + } +}, ['add [[<@scope>/]]', 'remove [[<@scope>/]]', 'list [<@scope>/]']); const run = _buildSubCommands.run, hasWrapper = _buildSubCommands.hasWrapper, @@ -95607,7 +94143,7 @@ exports.hasWrapper = hasWrapper; exports.examples = examples; /***/ }), -/* 526 */ +/* 508 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95616,7 +94152,13 @@ exports.examples = examples; Object.defineProperty(exports, "__esModule", { value: true }); -exports.run = undefined; +exports.examples = exports.setFlags = exports.run = undefined; + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); +} var _asyncToGenerator2; @@ -95624,173 +94166,273 @@ function _load_asyncToGenerator() { return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -let run = exports.run = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - const binFolder = path.join(config.cwd, config.registryFolders[0], '.bin'); - if (args.length === 0) { - reporter.log(binFolder, { force: true }); - } else { - const binEntries = yield (0, (_run || _load_run()).getBinEntries)(config); +let fetchReleases = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, { includePrereleases = false } = {}) { + const token = process.env.GITHUB_TOKEN; + const tokenUrlParameter = token ? `?access_token=${token}` : ''; - const binName = args[0]; - const binPath = binEntries.get(binName); + const request = yield config.requestManager.request({ + url: `https://api.github.com/repos/yarnpkg/yarn/releases${tokenUrlParameter}`, + json: true + }); - if (binPath) { - reporter.log(binPath, { force: true }); - } else { - reporter.error(reporter.lang('packageBinaryNotFound', binName)); + const releases = request.filter(function (release) { + if (release.draft) { + return false; } - } + + if (release.prerelease && !includePrereleases) { + return false; + } + + // $FlowFixMe + release.version = semver.coerce(release.tag_name); + + if (!release.version) { + return false; + } + + if (!getBundleAsset(release)) { + return false; + } + + return true; + }); + + releases.sort(function (a, b) { + // $FlowFixMe + return -semver.compare(a.version, b.version); + }); + + return releases; }); - return function run(_x, _x2, _x3, _x4) { + return function fetchReleases(_x) { return _ref.apply(this, arguments); }; })(); exports.hasWrapper = hasWrapper; -exports.setFlags = setFlags; -var _run; +var _yarnVersion; -function _load_run() { - return _run = __webpack_require__(360); +function _load_yarnVersion() { + return _yarnVersion = __webpack_require__(105); } -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const path = __webpack_require__(0); +var _child; -function hasWrapper(commander) { - return false; +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); } -function setFlags(commander) { - commander.description('Displays the location of the yarn bin folder.'); +var _buildSubCommands2; + +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); } -/***/ }), -/* 527 */ -/***/ (function(module, exports, __webpack_require__) { +var _rc; -"use strict"; +function _load_rc() { + return _rc = __webpack_require__(335); +} +var _fs; -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.examples = exports.run = undefined; +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} -var _asyncToGenerator2; +var _lockfile; -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +function _load_lockfile() { + return _lockfile = __webpack_require__(19); } -exports.hasWrapper = hasWrapper; -exports.setFlags = setFlags; +var _semver; -var _buildSubCommands2; +function _load_semver() { + return _semver = __webpack_require__(170); +} -function _load_buildSubCommands() { - return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); +var _constants; + +function _load_constants() { + return _constants = __webpack_require__(8); } +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 CONFIG_KEYS = [ -// 'reporter', -'registryFolders', 'linkedModules', -// 'registries', -'cache', 'cwd', 'looseSemver', 'commandName', 'preferOffline', 'modulesFolder', 'globalFolder', 'linkFolder', 'offline', 'binLinks', 'ignorePlatform', 'ignoreScripts', 'disablePrepublish', 'nonInteractive', 'workspaceRootFolder', 'lockfileFolder', 'networkConcurrency', 'childConcurrency', 'networkTimeout', 'workspacesEnabled', 'workspacesNohoistEnabled', 'pruneOfflineMirror', 'enableMetaFolder', 'enableLockfileVersions', 'linkFileDependencies', 'cacheFolder', 'tempFolder', 'production']; -/* eslint object-shorthand: 0 */ +/* eslint-disable max-len */ -function hasWrapper(flags, args) { - return args[0] !== 'get'; +const V2_NAMES = ['berry', 'stable', 'canary', 'v2', '2']; + +const isLocalFile = version => version.match(/^\.{0,2}[\\/]/) || path.isAbsolute(version); +const isV2Version = version => (0, (_semver || _load_semver()).satisfiesWithPrereleases)(version, '>=2.0.0'); + +const chalk = __webpack_require__(30); +const invariant = __webpack_require__(9); +const path = __webpack_require__(0); +const semver = __webpack_require__(22); + +function getBundleAsset(release) { + return release.assets.find(asset => { + return asset.name.match(/^yarn-[0-9]+\.[0-9]+\.[0-9]+\.js$/); + }); } -function setFlags(commander) { - commander.description('Manages the yarn configuration files.'); +function fetchBundle(config, url) { + return config.requestManager.request({ + url, + buffer: true + }); } -var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('config', { - set(config, reporter, flags, args) { - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (args.length === 0 || args.length > 2) { - return false; - } - const key = args[0]; - var _args$ = args[1]; - const val = _args$ === undefined ? true : _args$; +function hasWrapper(flags, args) { + return false; +} - const yarnConfig = config.registries.yarn; - yield yarnConfig.saveHomeConfig({ [key]: val }); - reporter.success(reporter.lang('configSet', key, val)); - return true; - })(); - }, +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('policies', { + setVersion(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const initialRange = args[0] || 'latest'; + let range = initialRange; - get(config, reporter, flags, args) { - if (args.length !== 1) { - return false; - } + let allowRc = flags.rc; - reporter.log(String(config.getOption(args[0])), { force: true }); - return true; - }, + if (range === 'rc') { + reporter.log(`${chalk.yellow(`Warning:`)} Your current Yarn binary is currently Yarn ${(_yarnVersion || _load_yarnVersion()).version}; to avoid potential breaking changes, 'set version rc' won't receive upgrades past the 1.22.x branch.\n To upgrade to the latest versions, run ${chalk.cyan(`yarn set version`)} ${chalk.yellow.underline(`canary`)} instead. Sorry for the inconvenience.\n`); - delete: (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - if (args.length !== 1) { - return false; + range = '*'; + allowRc = true; } - const key = args[0]; - const yarnConfig = config.registries.yarn; - yield yarnConfig.saveHomeConfig({ [key]: undefined }); - reporter.success(reporter.lang('configDelete', key)); - return true; - }); - - function _delete(_x, _x2, _x3, _x4) { - return _ref.apply(this, arguments); - } + if (range === 'latest') { + reporter.log(`${chalk.yellow(`Warning:`)} Your current Yarn binary is currently Yarn ${(_yarnVersion || _load_yarnVersion()).version}; to avoid potential breaking changes, 'set version latest' won't receive upgrades past the 1.22.x branch.\n To upgrade to the latest versions, run ${chalk.cyan(`yarn set version`)} ${chalk.yellow.underline(`stable`)} instead. Sorry for the inconvenience.\n`); - return _delete; - })(), + range = '*'; + } - list(config, reporter, flags, args) { - if (args.length) { - return false; - } + if (range === 'classic') { + range = '*'; + } - reporter.info(reporter.lang('configYarn')); - reporter.inspect(config.registries.yarn.config); + let bundleUrl; + let bundleVersion; + const isV2 = false; - reporter.info(reporter.lang('configNpm')); - reporter.inspect(config.registries.npm.config); + if (range === 'nightly' || range === 'nightlies') { + reporter.log(`${chalk.yellow(`Warning:`)} Nightlies only exist for Yarn 1.x; starting from 2.x onwards, you should use 'canary' instead`); - return true; - }, + bundleUrl = 'https://nightly.yarnpkg.com/latest.js'; + bundleVersion = 'nightly'; + } else if (V2_NAMES.includes(range) || isLocalFile(range) || isV2Version(range)) { + const normalizedRange = range === `canary` ? `canary` : `stable`; - current(config, reporter, flags, args) { - if (args.length) { - return false; - } + if (process.env.COREPACK_ROOT) { + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [path.join(process.env.COREPACK_ROOT, 'dist/corepack.js'), `yarn@${normalizedRange}`, `set`, `version`, normalizedRange], { + stdio: 'inherit', + cwd: config.cwd + }); - reporter.log(JSON.stringify(config, CONFIG_KEYS, 2), { force: true }); + return; + } else { + const bundle = yield fetchBundle(config, 'https://github.com/yarnpkg/berry/raw/master/packages/yarnpkg-cli/bin/yarn.js'); - return true; + const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-stable-temp.cjs`); + yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath)); + yield (_fs || _load_fs()).writeFile(yarnPath, bundle); + yield (_fs || _load_fs()).chmod(yarnPath, 0o755); + + try { + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [yarnPath, 'set', 'version', range], { + stdio: 'inherit', + cwd: config.lockfileFolder, + env: (0, (_extends2 || _load_extends()).default)({}, process.env, { + YARN_IGNORE_PATH: `1` + }) + }); + } catch (err) { + // eslint-disable-next-line no-process-exit + process.exit(1); + } + + return; + } + } else { + reporter.log(`Resolving ${chalk.yellow(initialRange)} to a url...`); + + let releases = []; + + try { + releases = yield fetchReleases(config, { + includePrereleases: allowRc + }); + } catch (e) { + reporter.error(e.message); + return; + } + + const release = releases.find(function (release) { + // $FlowFixMe + return semver.satisfies(release.version, range); + }); + + if (!release) { + throw new Error(`Release not found: ${range}`); + } + + const asset = getBundleAsset(release); + invariant(asset, 'The bundle asset should exist'); + + bundleUrl = asset.browser_download_url; + bundleVersion = release.version.version; + } + + reporter.log(`Downloading ${chalk.green(bundleUrl)}...`); + + const bundle = yield fetchBundle(config, bundleUrl); + + const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.cjs`); + reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`); + yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath)); + yield (_fs || _load_fs()).writeFile(yarnPath, bundle); + yield (_fs || _load_fs()).chmod(yarnPath, 0o755); + + const targetPath = path.relative(config.lockfileFolder, yarnPath).replace(/\\/g, '/'); + + if (isV2) { + const rcPath = `${config.lockfileFolder}/.yarnrc.yml`; + reporter.log(`Updating ${chalk.magenta(rcPath)}...`); + + yield (_fs || _load_fs()).writeFilePreservingEol(rcPath, `yarnPath: ${JSON.stringify(targetPath)}\n`); + } else { + const rcPath = `${config.lockfileFolder}/.yarnrc`; + reporter.log(`Updating ${chalk.magenta(rcPath)}...`); + + const rc = (0, (_rc || _load_rc()).getRcConfigForFolder)(config.lockfileFolder); + rc['yarn-path'] = targetPath; + + yield (_fs || _load_fs()).writeFilePreservingEol(rcPath, `${(0, (_lockfile || _load_lockfile()).stringify)(rc)}\n`); + } + + reporter.log(`Done!`); + })(); } }); const run = _buildSubCommands.run, + setFlags = _buildSubCommands.setFlags, examples = _buildSubCommands.examples; exports.run = run; +exports.setFlags = setFlags; exports.examples = examples; /***/ }), -/* 528 */ +/* 509 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95807,51 +94449,174 @@ function _load_asyncToGenerator() { return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -var _extends2; +let publish = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, pkg, flags, dir) { + let access = flags.access; -function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); -} + // if no access level is provided, check package.json for `publishConfig.access` + // see: https://docs.npmjs.com/files/package.json#publishconfig + if (!access && pkg && pkg.publishConfig && pkg.publishConfig.access) { + access = pkg.publishConfig.access; + } -let run = exports.run = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - const builderName = args[0], - rest = args.slice(1); + // validate access argument + if (access && access !== 'public' && access !== 'restricted') { + throw new (_errors || _load_errors()).MessageError(config.reporter.lang('invalidAccess')); + } + // TODO this might modify package.json, do we need to reload it? + yield config.executeLifecycleScript('prepublish'); + yield config.executeLifecycleScript('prepare'); + yield config.executeLifecycleScript('prepublishOnly'); + yield config.executeLifecycleScript('prepack'); - if (!builderName) { - throw new (_errors || _load_errors()).MessageError(reporter.lang('invalidPackageName')); + // get tarball stream + const stat = yield (_fs || _load_fs()).lstat(dir); + let stream; + if (stat.isDirectory()) { + stream = yield (0, (_pack || _load_pack()).pack)(config); + } else if (stat.isFile()) { + stream = fs2.createReadStream(dir); + } else { + throw new Error("Don't know how to handle this file type"); } + const buffer = yield new Promise(function (resolve, reject) { + const data = []; + invariant(stream, 'expected stream'); + stream.on('data', data.push.bind(data)).on('end', function () { + return resolve(Buffer.concat(data)); + }).on('error', reject); + }); - var _coerceCreatePackageN = coerceCreatePackageName(builderName); + yield config.executeLifecycleScript('postpack'); - const packageName = _coerceCreatePackageN.fullName, - commandName = _coerceCreatePackageN.name; + // copy normalized package and remove internal keys as they may be sensitive or yarn specific + pkg = Object.assign({}, pkg); + for (const key in pkg) { + if (key[0] === '_') { + delete pkg[key]; + } + } + const tag = flags.tag || 'latest'; + const tbName = `${pkg.name}-${pkg.version}.tgz`; + const tbURI = `${pkg.name}/-/${tbName}`; - const linkLoc = path.join(config.linkFolder, commandName); - if (yield (_fs || _load_fs()).exists(linkLoc)) { - reporter.info(reporter.lang('linkUsing', packageName)); - } else { - yield (0, (_global || _load_global()).run)(config, reporter, {}, ['add', packageName]); - } + // create body + const root = { + _id: pkg.name, + access, + name: pkg.name, + description: pkg.description, + 'dist-tags': { + [tag]: pkg.version + }, + versions: { + [pkg.version]: pkg + }, + readme: pkg.readme || '', + _attachments: { + [tbName]: { + content_type: 'application/octet-stream', + data: buffer.toString('base64'), + length: buffer.length + } + } + }; - const binFolder = yield (0, (_global || _load_global()).getBinFolder)(config, {}); - const command = path.resolve(binFolder, commandName); - const env = yield (0, (_executeLifecycleScript || _load_executeLifecycleScript()).makeEnv)('create', config.cwd, config); + pkg._id = `${pkg.name}@${pkg.version}`; + pkg.dist = pkg.dist || {}; + pkg.dist.shasum = crypto.createHash('sha1').update(buffer).digest('hex'); + pkg.dist.integrity = ssri.fromData(buffer).toString(); - yield (_child || _load_child()).spawn(command, rest, { stdio: `inherit`, shell: true, env }); + const registry = String(config.getOption('registry')); + pkg.dist.tarball = url.resolve(registry, tbURI).replace(/^https:\/\//, 'http://'); + + // publish package + try { + yield config.registries.npm.request((_npmRegistry || _load_npmRegistry()).default.escapeName(pkg.name), { + registry: pkg && pkg.publishConfig && pkg.publishConfig.registry, + method: 'PUT', + body: root + }); + } catch (error) { + throw new (_errors || _load_errors()).MessageError(config.reporter.lang('publishFail', error.message)); + } + + yield config.executeLifecycleScript('publish'); + yield config.executeLifecycleScript('postpublish'); }); - return function run(_x, _x2, _x3, _x4) { + return function publish(_x, _x2, _x3, _x4) { return _ref.apply(this, arguments); }; })(); +let run = exports.run = (() => { + var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + // validate arguments + const dir = args[0] ? (_path || _load_path()).default.resolve(config.cwd, args[0]) : config.cwd; + if (args.length > 1) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('tooManyArguments', 1)); + } + if (!(yield (_fs || _load_fs()).exists(dir))) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('unknownFolderOrTarball')); + } + + const stat = yield (_fs || _load_fs()).lstat(dir); + let publishPath = dir; + if (stat.isDirectory()) { + config.cwd = (_path || _load_path()).default.resolve(dir); + publishPath = config.cwd; + } + + // validate package fields that are required for publishing + // $FlowFixMe + const pkg = yield config.readRootManifest(); + if (pkg.private) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('publishPrivate')); + } + if (!pkg.name) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('noName')); + } + + let registry = ''; + + if (pkg && pkg.publishConfig && pkg.publishConfig.registry) { + registry = pkg.publishConfig.registry; + } + + reporter.step(1, 4, reporter.lang('bumpingVersion')); + const commitVersion = yield (0, (_version || _load_version()).setVersion)(config, reporter, flags, [], false); + + // + reporter.step(2, 4, reporter.lang('loggingIn')); + const revoke = yield (0, (_login || _load_login()).getToken)(config, reporter, pkg.name, flags, registry); + + // + reporter.step(3, 4, reporter.lang('publishing')); + yield publish(config, pkg, flags, publishPath); + yield commitVersion(); + reporter.success(reporter.lang('published')); + + // + reporter.step(4, 4, reporter.lang('revokingToken')); + yield revoke(); + }); + + return function run(_x5, _x6, _x7, _x8) { + return _ref2.apply(this, arguments); + }; +})(); + exports.setFlags = setFlags; exports.hasWrapper = hasWrapper; -exports.parsePackageName = parsePackageName; -exports.coerceCreatePackageName = coerceCreatePackageName; + +var _npmRegistry; + +function _load_npmRegistry() { + return _npmRegistry = _interopRequireDefault(__webpack_require__(88)); +} var _errors; @@ -95859,78 +94624,302 @@ function _load_errors() { return _errors = __webpack_require__(6); } -var _child; +var _version; -function _load_child() { - return _child = _interopRequireWildcard(__webpack_require__(58)); +function _load_version() { + return _version = __webpack_require__(357); } -var _executeLifecycleScript; +var _fs; -function _load_executeLifecycleScript() { - return _executeLifecycleScript = __webpack_require__(111); +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); } -var _fs; +var _pack; -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); +function _load_pack() { + return _pack = __webpack_require__(166); } -var _global; +var _login; -function _load_global() { - return _global = __webpack_require__(121); +function _load_login() { + return _login = __webpack_require__(107); +} + +var _path; + +function _load_path() { + return _path = _interopRequireDefault(__webpack_require__(0)); } 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 path = __webpack_require__(0); +const invariant = __webpack_require__(9); + +const crypto = __webpack_require__(11); +const url = __webpack_require__(24); +const fs2 = __webpack_require__(4); +const ssri = __webpack_require__(65); function setFlags(commander) { - commander.description('Creates new projects from any create-* starter kits.'); + (0, (_version || _load_version()).setFlags)(commander); + commander.description('Publishes a package to the npm registry.'); + commander.usage('publish [|] [--tag ] [--access ]'); + commander.option('--access [access]', 'access'); + commander.option('--tag [tag]', 'tag'); } function hasWrapper(commander, args) { return true; } -function parsePackageName(str) { - if (str.charAt(0) === '/') { - throw new Error(`Name should not start with "/", got "${str}"`); - } - if (str.charAt(0) === '.') { - throw new Error(`Name should not start with ".", got "${str}"`); +/***/ }), +/* 510 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.examples = exports.hasWrapper = exports.run = undefined; + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(20)); +} + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let removeTeamUser = (() => { + var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (parts, config, reporter) { + reporter.step(2, 3, reporter.lang('teamRemovingUser')); + reporter.inspect((yield config.registries.npm.request(`team/${parts.scope}/${parts.team}/user`, { + method: 'DELETE', + body: { + user: parts.user + } + }))); + return true; + }); + + return function removeTeamUser(_x5, _x6, _x7) { + return _ref2.apply(this, arguments); + }; +})(); + +let list = (() => { + var _ref3 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (parts, config, reporter) { + reporter.step(2, 3, reporter.lang('teamListing')); + const uriParams = '?format=cli'; + if (parts.team) { + reporter.inspect((yield config.registries.npm.request(`team/${parts.scope}/${parts.team}/user${uriParams}`))); + } else { + reporter.inspect((yield config.registries.npm.request(`org/${parts.scope}/team${uriParams}`))); + } + return true; + }); + + return function list(_x8, _x9, _x10) { + return _ref3.apply(this, arguments); + }; +})(); + +exports.setFlags = setFlags; + +var _buildSubCommands2; + +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); +} + +var _login; + +function _load_login() { + return _login = __webpack_require__(107); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function explodeScopeTeam(arg, requireTeam, reporter) { + var _arg$split = arg.split(':'); + + const scope = _arg$split[0], + team = _arg$split[1], + parts = _arg$split.slice(2); + + if (parts.length) { + return false; } - const parts = str.split('/'); - const isScoped = str.charAt(0) === '@'; - if (isScoped && parts[0] === '@') { - throw new Error(`Scope should not be empty, got "${str}"`); + + if (requireTeam && !team) { + return false; } - const scope = isScoped ? parts[0] : ''; - const name = parts[isScoped ? 1 : 0] || ''; - const path = parts.slice(isScoped ? 2 : 1).join('/'); - const fullName = [scope, name].filter(Boolean).join('/'); - const full = [scope, name, path].filter(Boolean).join('/'); - return { fullName, name, scope, path, full }; + return { + scope: scope || '', + team: team || '', + user: '' + }; } -function coerceCreatePackageName(str) { - const pkgNameObj = parsePackageName(str); - const coercedName = pkgNameObj.name !== '' ? `create-${pkgNameObj.name}` : `create`; - const coercedPkgNameObj = (0, (_extends2 || _load_extends()).default)({}, pkgNameObj, { - name: coercedName, - fullName: [pkgNameObj.scope, coercedName].filter(Boolean).join('/'), - full: [pkgNameObj.scope, coercedName, pkgNameObj.path].filter(Boolean).join('/') - }); - return coercedPkgNameObj; +function warnDeprecation(reporter, deprecationWarning) { + const command = 'yarn team'; + reporter.warn(reporter.lang('deprecatedCommand', `${command} ${deprecationWarning.deprecatedCommand}`, `${command} ${deprecationWarning.currentCommand}`)); +} + +function wrapRequired(callback, requireTeam, deprecationInfo) { + return (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + if (deprecationInfo) { + warnDeprecation(reporter, deprecationInfo); + } + + if (!args.length) { + return false; + } + + const parts = explodeScopeTeam(args[0], requireTeam, reporter); + if (!parts) { + return false; + } + + reporter.step(1, 3, reporter.lang('loggingIn')); + const revoke = yield (0, (_login || _load_login()).getToken)(config, reporter); + + const res = yield callback(parts, config, reporter, flags, args); + if (!res) { + return res; + } + + reporter.step(3, 3, reporter.lang('revokingToken')); + yield revoke(); + return true; + }); + + return function (_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; + })(); +} + +function wrapRequiredTeam(callback, requireTeam = true, subCommandDeprecated) { + return wrapRequired(function (parts, config, reporter, flags, args) { + if (args.length === 1) { + return callback(parts, config, reporter, flags, args); + } else { + return false; + } + }, requireTeam, subCommandDeprecated); +} + +function wrapRequiredUser(callback, subCommandDeprecated) { + return wrapRequired(function (parts, config, reporter, flags, args) { + if (args.length === 2) { + return callback((0, (_extends2 || _load_extends()).default)({ + user: args[1] + }, parts), config, reporter, flags, args); + } else { + return false; + } + }, true, subCommandDeprecated); +} + +function setFlags(commander) { + commander.description('Maintain team memberships'); } +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('team', { + create: wrapRequiredTeam((() => { + var _ref4 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (parts, config, reporter, flags, args) { + reporter.step(2, 3, reporter.lang('teamCreating')); + reporter.inspect((yield config.registries.npm.request(`team/${parts.scope}`, { + method: 'PUT', + body: { + team: parts.team + } + }))); + return true; + }); + + return function (_x11, _x12, _x13, _x14, _x15) { + return _ref4.apply(this, arguments); + }; + })()), + + destroy: wrapRequiredTeam((() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (parts, config, reporter, flags, args) { + reporter.step(2, 3, reporter.lang('teamRemoving')); + reporter.inspect((yield config.registries.npm.request(`team/${parts.scope}/${parts.team}`, { + method: 'DELETE' + }))); + return true; + }); + + return function (_x16, _x17, _x18, _x19, _x20) { + return _ref5.apply(this, arguments); + }; + })()), + + add: wrapRequiredUser((() => { + var _ref6 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (parts, config, reporter, flags, args) { + reporter.step(2, 3, reporter.lang('teamAddingUser')); + reporter.inspect((yield config.registries.npm.request(`team/${parts.scope}/${parts.team}/user`, { + method: 'PUT', + body: { + user: parts.user + } + }))); + return true; + }); + + return function (_x21, _x22, _x23, _x24, _x25) { + return _ref6.apply(this, arguments); + }; + })()), + + rm: wrapRequiredUser(function (parts, config, reporter, flags, args) { + removeTeamUser(parts, config, reporter); + }, { + deprecatedCommand: 'rm', + currentCommand: 'remove' + }), + + remove: wrapRequiredUser(function (parts, config, reporter, flags, args) { + removeTeamUser(parts, config, reporter); + }), + + ls: wrapRequiredTeam(function (parts, config, reporter, flags, args) { + list(parts, config, reporter); + }, false, { + deprecatedCommand: 'ls', + currentCommand: 'list' + }), + + list: wrapRequiredTeam(function (parts, config, reporter, flags, args) { + list(parts, config, reporter); + }, false) +}, ['create ', 'destroy ', 'add ', 'remove ', 'list |']); + +const run = _buildSubCommands.run, + hasWrapper = _buildSubCommands.hasWrapper, + examples = _buildSubCommands.examples; +exports.run = run; +exports.hasWrapper = hasWrapper; +exports.examples = examples; + /***/ }), -/* 529 */ +/* 511 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95949,16 +94938,63 @@ function _load_asyncToGenerator() { let run = exports.run = (() => { var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - const env = yield (0, (_executeLifecycleScript || _load_executeLifecycleScript()).makeEnv)(`exec`, config.cwd, config); + if (args.length) { + for (var _iterator = args, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref2; - if (args.length < 1) { - throw new (_errors || _load_errors()).MessageError(reporter.lang('execMissingCommand')); - } + if (_isArray) { + if (_i >= _iterator.length) break; + _ref2 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref2 = _i.value; + } - const execName = args[0], - rest = args.slice(1); + const name = _ref2; - yield (_child || _load_child()).spawn(execName, rest, { stdio: 'inherit', env }); + const linkLoc = path.join(config.linkFolder, name); + if (yield (_fs || _load_fs()).exists(linkLoc)) { + yield (_fs || _load_fs()).unlink(path.join((yield (0, (_link || _load_link()).getRegistryFolder)(config, name)), name)); + reporter.success(reporter.lang('linkDisusing', name)); + reporter.info(reporter.lang('linkDisusingMessage', name)); + } else { + throw new (_errors || _load_errors()).MessageError(reporter.lang('linkMissing', name)); + } + } + } else { + // remove from registry + const manifest = yield config.readRootManifest(); + const name = manifest.name; + if (!name) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('unknownPackageName')); + } + + const linkLoc = path.join(config.linkFolder, name); + if (yield (_fs || _load_fs()).exists(linkLoc)) { + // If there is a `bin` defined in the package.json, + // link each bin to the global bin + if (manifest.bin) { + const globalBinFolder = yield (0, (_global || _load_global()).getBinFolder)(config, flags); + for (const binName in manifest.bin) { + const binDestLoc = path.join(globalBinFolder, binName); + if (yield (_fs || _load_fs()).exists(binDestLoc)) { + yield (_fs || _load_fs()).unlink(binDestLoc); + if (process.platform === 'win32') { + yield (_fs || _load_fs()).unlink(binDestLoc + '.cmd'); + } + } + } + } + + yield (_fs || _load_fs()).unlink(linkLoc); + + reporter.success(reporter.lang('linkUnregistered', name)); + reporter.info(reporter.lang('linkUnregisteredMessage', name)); + } else { + throw new (_errors || _load_errors()).MessageError(reporter.lang('linkMissing', name)); + } + } }); return function run(_x, _x2, _x3, _x4) { @@ -95975,30 +95011,40 @@ function _load_errors() { return _errors = __webpack_require__(6); } -var _child; +var _fs; -function _load_child() { - return _child = _interopRequireWildcard(__webpack_require__(58)); +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); } -var _executeLifecycleScript; +var _link; -function _load_executeLifecycleScript() { - return _executeLifecycleScript = __webpack_require__(111); +function _load_link() { + return _link = __webpack_require__(351); +} + +var _global; + +function _load_global() { + return _global = __webpack_require__(121); } 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 }; } -function setFlags(commander) {} +const path = __webpack_require__(0); + +function setFlags(commander) { + commander.description('Unlink a previously created symlink for a package.'); +} function hasWrapper(commander, args) { return true; } /***/ }), -/* 530 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96007,7 +95053,7 @@ function hasWrapper(commander, args) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.examples = exports.run = undefined; +exports.clearAll = exports.clearSome = exports.run = undefined; var _asyncToGenerator2; @@ -96017,31 +95063,47 @@ function _load_asyncToGenerator() { let run = exports.run = (() => { var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - let manifest; - if (flags.useManifest) { - manifest = yield config.readJson(flags.useManifest); - } else { - manifest = yield config.readRootManifest(); + if (!config.plugnplayEnabled) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('unplugDisabled')); } - if (!manifest.name) { - throw new (_errors || _load_errors()).MessageError(reporter.lang('noName')); + if (!args.length && flags.clear) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('tooFewArguments', 1)); } - if (!manifest.version) { - throw new (_errors || _load_errors()).MessageError(reporter.lang('noVersion')); + if (args.length && flags.clearAll) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('noArguments')); } - const entry = { - name: manifest.name, - version: manifest.version, - resolved: flags.resolved, - registry: flags.registry || manifest._registry, - optionalDependencies: manifest.optionalDependencies, - dependencies: manifest.dependencies - }; - const pattern = flags.pattern || `${entry.name}@${entry.version}`; - reporter.log((0, (_lockfile || _load_lockfile()).stringify)({ - [pattern]: (0, (_lockfile || _load_lockfile()).implodeEntry)(pattern, entry) - })); + if (flags.clearAll) { + yield clearAll(config); + } else if (flags.clear) { + yield clearSome(config, new Set(args)); + } else if (args.length > 0) { + const lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); + yield (0, (_install || _load_install()).wrapLifecycle)(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const install = new (_install || _load_install()).Install(flags, config, reporter, lockfile); + install.linker.unplugged = args; + yield install.init(); + })); + } + + const unpluggedPackageFolders = yield config.listUnpluggedPackageFolders(); + + for (var _iterator = unpluggedPackageFolders.values(), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref3; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref3 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref3 = _i.value; + } + + const target = _ref3; + + reporter.log(target, { force: true }); + } }); return function run(_x, _x2, _x3, _x4) { @@ -96049,147 +95111,121 @@ let run = exports.run = (() => { }; })(); -exports.hasWrapper = hasWrapper; -exports.setFlags = setFlags; +let clearSome = exports.clearSome = (() => { + var _ref4 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, filters) { + const unpluggedPackageFolders = yield config.listUnpluggedPackageFolders(); + const removeList = []; -var _errors; + for (var _iterator2 = unpluggedPackageFolders.entries(), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref6; -function _load_errors() { - return _errors = __webpack_require__(6); -} + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref6 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref6 = _i2.value; + } -var _lockfile; + const _ref5 = _ref6; + const unpluggedName = _ref5[0]; + const target = _ref5[1]; -function _load_lockfile() { - return _lockfile = __webpack_require__(19); -} + var _ref8 = yield (_fs || _load_fs()).readJson(path.join(target, 'package.json')); -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + const name = _ref8.name; -function hasWrapper(commander, args) { - return false; -} + const toBeRemoved = filters.has(name); -function setFlags(commander) { - commander.description('Generates a lock file entry.'); - commander.option('--use-manifest ', 'description'); - commander.option('--resolved ', 'description'); - commander.option('--registry ', 'description'); -} + if (toBeRemoved) { + removeList.push(path.join(config.getUnpluggedPath(), unpluggedName)); + } + } -const examples = exports.examples = ['generate-lock-entry', 'generate-lock-entry --use-manifest ./package.json', 'generate-lock-entry --resolved local-file.tgz#hash']; + if (removeList.length === unpluggedPackageFolders.size) { + yield (_fs || _load_fs()).unlink(config.getUnpluggedPath()); + } else { + for (var _iterator3 = removeList, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref7; -/***/ }), -/* 531 */ -/***/ (function(module, exports, __webpack_require__) { + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref7 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref7 = _i3.value; + } -"use strict"; + const unpluggedPackagePath = _ref7; + yield (_fs || _load_fs()).unlink(unpluggedPackagePath); + } + } + }); + + return function clearSome(_x5, _x6) { + return _ref4.apply(this, arguments); + }; +})(); + +let clearAll = exports.clearAll = (() => { + var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config) { + yield (_fs || _load_fs()).unlink(config.getUnpluggedPath()); + }); + + return function clearAll(_x7) { + return _ref9.apply(this, arguments); + }; +})(); -Object.defineProperty(exports, "__esModule", { - value: true -}); exports.hasWrapper = hasWrapper; exports.setFlags = setFlags; -exports.run = run; -var _index; +var _lockfile; -function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(334)); +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); } -var _constants; +var _install; -function _load_constants() { - return _constants = _interopRequireWildcard(__webpack_require__(8)); +function _load_install() { + return _install = __webpack_require__(34); } -var _misc; +var _errors; -function _load_misc() { - return _misc = __webpack_require__(18); +function _load_errors() { + return _errors = __webpack_require__(6); } -var _aliases; +var _fs; -function _load_aliases() { - return _aliases = _interopRequireDefault(__webpack_require__(352)); +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); } 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 chalk = __webpack_require__(30); +const path = __webpack_require__(0); -function hasWrapper(flags, args) { - return false; +function hasWrapper(commander) { + return true; } function setFlags(commander) { - commander.description('Displays help information.'); -} - -function run(config, reporter, commander, args) { - if (args.length) { - const commandName = args.shift(); - if (Object.prototype.hasOwnProperty.call((_index || _load_index()).default, commandName)) { - const command = (_index || _load_index()).default[commandName]; - if (command) { - command.setFlags(commander); - const examples = (command.examples || []).map(example => ` $ yarn ${example}`); - if (examples.length) { - commander.on('--help', () => { - reporter.log(reporter.lang('helpExamples', reporter.rawText(examples.join('\n')))); - }); - } - // eslint-disable-next-line yarn-internal/warn-language - commander.on('--help', () => reporter.log(' ' + command.getDocsInfo + '\n')); - commander.help(); - return Promise.resolve(); - } - } - } - - commander.on('--help', () => { - const commandsText = []; - for (var _iterator = Object.keys((_index || _load_index()).default).sort((_misc || _load_misc()).sortAlpha), _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 name = _ref; - - if ((_index || _load_index()).default[name].useless || Object.keys((_aliases || _load_aliases()).default).map(key => (_aliases || _load_aliases()).default[key]).indexOf(name) > -1) { - continue; - } - if ((_aliases || _load_aliases()).default[name]) { - commandsText.push(` - ${(0, (_misc || _load_misc()).hyphenate)(name)} / ${(_aliases || _load_aliases()).default[name]}`); - } else { - commandsText.push(` - ${(0, (_misc || _load_misc()).hyphenate)(name)}`); - } - } - reporter.log(reporter.lang('helpCommands', reporter.rawText(commandsText.join('\n')))); - reporter.log(reporter.lang('helpCommandsMore', reporter.rawText(chalk.bold('yarn help COMMAND')))); - reporter.log(reporter.lang('helpLearnMore', reporter.rawText(chalk.bold((_constants || _load_constants()).YARN_DOCS)))); - }); - - commander.options.sort((_misc || _load_misc()).sortOptionsByFlags); - - commander.help(); - return Promise.resolve(); + commander.description('Temporarily copies a package (with an optional @range suffix) outside of the global cache for debugging purposes'); + commander.usage('unplug [packages ...] [flags]'); + commander.option('--clear', 'Delete the selected packages'); + commander.option('--clear-all', 'Delete all unplugged packages'); } /***/ }), -/* 532 */ +/* 513 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96198,7 +95234,7 @@ function run(config, reporter, commander, args) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.run = exports.Import = exports.noArguments = undefined; +exports.run = undefined; var _asyncToGenerator2; @@ -96207,611 +95243,478 @@ function _load_asyncToGenerator() { } let run = exports.run = (() => { - var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - const imp = new Import(flags, config, reporter, new (_lockfile || _load_lockfile()).default({ cache: {} })); - yield imp.init(); + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const versions = { yarn: (_yarnVersion || _load_yarnVersion()).version }; + + const pkg = yield config.maybeReadManifest(config.cwd); + if (pkg && pkg.name && pkg.version) { + versions[pkg.name] = pkg.version; + } + + Object.assign(versions, process.versions); + + reporter.inspect(versions); }); return function run(_x, _x2, _x3, _x4) { - return _ref5.apply(this, arguments); + return _ref.apply(this, arguments); }; })(); exports.setFlags = setFlags; exports.hasWrapper = hasWrapper; -var _install; +var _yarnVersion; -function _load_install() { - return _install = __webpack_require__(34); +function _load_yarnVersion() { + return _yarnVersion = __webpack_require__(105); } -var _check; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function _load_check() { - return _check = __webpack_require__(356); +function setFlags(commander) { + commander.description('Displays version information of currently installed Yarn, Node.js, and its dependencies.'); } -var _errors; - -function _load_errors() { - return _errors = __webpack_require__(6); +function hasWrapper(commander, args) { + return true; } -var _index; +/***/ }), +/* 514 */ +/***/ (function(module, exports, __webpack_require__) { -function _load_index() { - return _index = __webpack_require__(78); -} +"use strict"; -var _baseResolver; -function _load_baseResolver() { - return _baseResolver = _interopRequireDefault(__webpack_require__(123)); -} +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = exports.requireLockfile = undefined; -var _hostedGitResolver; +var _asyncToGenerator2; -function _load_hostedGitResolver() { - return _hostedGitResolver = _interopRequireDefault(__webpack_require__(109)); +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -var _hostedGitResolver2; +let cleanQuery = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, query) { + // if a location was passed then turn it into a hash query + if (path.isAbsolute(query) && (yield (_fs || _load_fs()).exists(query))) { + // absolute path + query = path.relative(config.cwd, query); + } -function _load_hostedGitResolver2() { - return _hostedGitResolver2 = __webpack_require__(109); -} + // remove references to node_modules with hashes + query = query.replace(/([\\/]|^)node_modules[\\/]/g, '#'); -var _gistResolver; + // remove trailing hashes + query = query.replace(/^#+/g, ''); -function _load_gistResolver() { - return _gistResolver = _interopRequireDefault(__webpack_require__(216)); -} + // remove trailing paths from each part of the query, skip second part of path for scoped packages + let queryParts = query.split('#'); + queryParts = queryParts.map(function (part) { + let parts = part.split(/[\\/]/g); -var _gistResolver2; + if (part[0] === '@') { + parts = parts.slice(0, 2); + } else { + parts = parts.slice(0, 1); + } -function _load_gistResolver2() { - return _gistResolver2 = __webpack_require__(216); -} + return parts.join('/'); + }); + query = queryParts.join('#'); -var _gitResolver; + return query; + }); -function _load_gitResolver() { - return _gitResolver = _interopRequireDefault(__webpack_require__(124)); -} + return function cleanQuery(_x, _x2) { + return _ref.apply(this, arguments); + }; +})(); -var _fileResolver; +let getPackageSize = (() => { + var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (tuple) { + const loc = tuple[0]; -function _load_fileResolver() { - return _fileResolver = _interopRequireDefault(__webpack_require__(215)); -} -var _packageResolver; + const files = yield (_fs || _load_fs()).walk(loc, null, new Set([(_constants || _load_constants()).METADATA_FILENAME, (_constants || _load_constants()).TARBALL_FILENAME])); -function _load_packageResolver() { - return _packageResolver = _interopRequireDefault(__webpack_require__(366)); -} + const sizes = yield Promise.all(files.map(function (walkFile) { + return (_fs || _load_fs()).getFileSizeOnDisk(walkFile.absolute); + })); -var _packageRequest; + return sum(sizes); + }); -function _load_packageRequest() { - return _packageRequest = _interopRequireDefault(__webpack_require__(122)); -} + return function getPackageSize(_x3) { + return _ref2.apply(this, arguments); + }; +})(); -var _packageReference; +let run = exports.run = (() => { + var _ref6 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + if (!args.length) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('missingWhyDependency')); + } + if (args.length > 1) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('tooManyArguments', 1)); + } -function _load_packageReference() { - return _packageReference = _interopRequireDefault(__webpack_require__(365)); -} + const query = yield cleanQuery(config, args[0]); -var _packageFetcher; + reporter.step(1, 4, reporter.lang('whyStart', args[0]), emoji.get('thinking_face')); -function _load_packageFetcher() { - return _packageFetcher = _interopRequireWildcard(__webpack_require__(210)); -} + // init + reporter.step(2, 4, reporter.lang('whyInitGraph'), emoji.get('truck')); + const lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); + const install = new (_install || _load_install()).Install(flags, config, reporter, lockfile); -var _packageLinker; + var _ref7 = yield install.fetchRequestFromCwd(); -function _load_packageLinker() { - return _packageLinker = _interopRequireDefault(__webpack_require__(211)); -} + const depRequests = _ref7.requests, + patterns = _ref7.patterns, + workspaceLayout = _ref7.workspaceLayout; -var _packageCompatibility; + yield install.resolver.init(depRequests, { + isFlat: install.flags.flat, + isFrozen: install.flags.frozenLockfile, + workspaceLayout + }); + const hoisted = yield install.linker.getFlatHoistedTree(patterns); -function _load_packageCompatibility() { - return _packageCompatibility = _interopRequireWildcard(__webpack_require__(209)); -} + // finding + reporter.step(3, 4, reporter.lang('whyFinding'), emoji.get('mag')); -var _lockfile; + const matches = queryWhy(query, hoisted); -function _load_lockfile() { - return _lockfile = _interopRequireDefault(__webpack_require__(19)); -} - -var _normalizePattern9; - -function _load_normalizePattern() { - return _normalizePattern9 = __webpack_require__(37); -} - -var _logicalDependencyTree; + if (matches.length <= 0) { + reporter.error(reporter.lang('whyUnknownMatch')); + return; + } -function _load_logicalDependencyTree() { - return _logicalDependencyTree = __webpack_require__(582); -} + const processMatch = (() => { + var _ref8 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (match) { + const matchInfo = match[1]; -var _fs; + const matchRef = matchInfo.pkg._reference; + invariant(matchRef, 'expected reference'); -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); -} + const distinctMatchPatterns = new Set(matchRef.patterns); + const reasons = []; -var _misc; + // reason: dependency of these modules + if (matchInfo.originalParentPath.length > 0) { + reasons.push({ + type: 'whyDependedOn', + typeSimple: 'whyDependedOnSimple', + value: toStandardPathString(matchInfo.originalParentPath) + }); + } -function _load_misc() { - return _misc = _interopRequireWildcard(__webpack_require__(18)); -} + // reason: exists in manifest + let rootType; + for (var _iterator3 = distinctMatchPatterns, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref9; -var _constants; + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref9 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref9 = _i3.value; + } -function _load_constants() { - return _constants = __webpack_require__(8); -} + const pattern = _ref9; -var _semver; + rootType = install.rootPatternsToOrigin[pattern]; + if (rootType) { + reasons.push({ + type: 'whySpecified', + typeSimple: 'whySpecifiedSimple', + value: rootType + }); + } + } -function _load_semver() { - return _semver = _interopRequireDefault(__webpack_require__(22)); -} + // reason: this is hoisted from these modules + for (var _iterator4 = matchInfo.previousPaths, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref10; -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; } } + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref10 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref10 = _i4.value; + } -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + const path = _ref10; -const invariant = __webpack_require__(9); -const path = __webpack_require__(0); -const uuid = __webpack_require__(119); -const ssri = __webpack_require__(65); -const nodeVersion = process.versions.node.split('-')[0]; + reasons.push({ + type: 'whyHoistedFrom', + typeSimple: 'whyHoistedFromSimple', + value: toStandardPathString(path) + }); + } -const noArguments = exports.noArguments = true; + // package sizes + let packageSize = 0; + let directSizes = []; + let transitiveSizes = []; + try { + packageSize = yield getPackageSize(match); + } catch (e) {} -class ImportResolver extends (_baseResolver || _load_baseResolver()).default { - getCwd() { - if (this.request.parentRequest) { - const parent = this.resolver.getStrictResolvedPattern(this.request.parentRequest.pattern); - invariant(parent._loc, 'expected package location'); - return path.dirname(parent._loc); - } - return this.config.cwd; - } + const dependencies = Array.from(collect(hoisted, new Set(), match)); + const transitiveDependencies = Array.from(collect(hoisted, new Set(), match, { recursive: true })); - resolveHostedGit(info, Resolver) { - var _normalizePattern = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + try { + directSizes = yield Promise.all(dependencies.map(getPackageSize)); + transitiveSizes = yield Promise.all(transitiveDependencies.map(getPackageSize)); + } catch (e) {} - const range = _normalizePattern.range; + const transitiveKeys = new Set(transitiveDependencies.map(function ([, info]) { + return info.key; + })); + const sharedDependencies = getSharedDependencies(hoisted, transitiveKeys); - const exploded = (0, (_hostedGitResolver2 || _load_hostedGitResolver2()).explodeHostedGitFragment)(range, this.reporter); - const hash = info.gitHead; - invariant(hash, 'expected package gitHead'); - const url = Resolver.getTarballUrl(exploded, hash); - info._uid = hash; - info._remote = { - resolved: url, - type: 'tarball', - registry: this.registry, - reference: url, - hash: null - }; - return info; - } + // prepare output: populate reporter + reporter.info(reporter.lang('whyMatch', `${matchInfo.key}@${matchInfo.pkg.version}`)); + // + // reason: hoisted/nohoist + if (matchInfo.isNohoist) { + reasons.push({ + type: 'whyNotHoisted', + typeSimple: 'whyNotHoistedSimple', + value: matchInfo.nohoistList + }); + } else if (query === matchInfo.originalKey) { + reporter.info(reporter.lang('whyHoistedTo', matchInfo.key)); + } - resolveGist(info, Resolver) { - var _normalizePattern2 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + if (reasons.length === 1) { + reporter.info(reporter.lang(reasons[0].typeSimple, reasons[0].value)); + } else if (reasons.length > 1) { + reporter.info(reporter.lang('whyReasons')); + reporter.list('reasons', reasons.map(function (reason) { + return reporter.lang(reason.type, reason.value); + })); + } else { + reporter.error(reporter.lang('whyWhoKnows')); + } - const range = _normalizePattern2.range; + if (packageSize) { + // stats: file size of this dependency without any dependencies + reporter.info(reporter.lang('whyDiskSizeWithout', bytes(packageSize))); - var _explodeGistFragment = (0, (_gistResolver2 || _load_gistResolver2()).explodeGistFragment)(range, this.reporter); + // stats: file size of this dependency including dependencies that aren't shared + reporter.info(reporter.lang('whyDiskSizeUnique', bytes(packageSize + sum(directSizes)))); - const id = _explodeGistFragment.id; + // stats: file size of this dependency including dependencies + reporter.info(reporter.lang('whyDiskSizeTransitive', bytes(packageSize + sum(transitiveSizes)))); - const hash = info.gitHead; - invariant(hash, 'expected package gitHead'); - const url = `https://gist.github.com/${id}.git`; - info._uid = hash; - info._remote = { - resolved: `${url}#${hash}`, - type: 'git', - registry: this.registry, - reference: url, - hash - }; - return info; - } + // stats: shared transitive dependencies + reporter.info(reporter.lang('whySharedDependencies', sharedDependencies.size)); + } + }); - resolveGit(info, Resolver) { - const url = info._resolved; - const hash = info.gitHead; - invariant(url, 'expected package _resolved'); - invariant(hash, 'expected package gitHead'); - info._uid = hash; - info._remote = { - resolved: `${url}#${hash}`, - type: 'git', - registry: this.registry, - reference: url, - hash - }; - return info; - } + return function processMatch(_x8) { + return _ref8.apply(this, arguments); + }; + })(); - resolveFile(info, Resolver) { - var _normalizePattern3 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + reporter.step(4, 4, reporter.lang('whyCalculating'), emoji.get('aerial_tramway')); + for (var _iterator5 = matches, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref11; - const range = _normalizePattern3.range; + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref11 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref11 = _i5.value; + } - let loc = (_misc || _load_misc()).removePrefix(range, 'file:'); - if (!path.isAbsolute(loc)) { - loc = path.join(this.config.cwd, loc); - } - info._uid = info.version; - info._remote = { - type: 'copy', - registry: this.registry, - hash: `${uuid.v4()}-${new Date().getTime()}`, - reference: loc - }; - return info; - } + const match = _ref11; - resolveRegistry(info) { - let url = info._resolved; - const hash = info._shasum; - invariant(url, 'expected package _resolved'); - invariant(hash, 'expected package _shasum'); - if (this.config.getOption('registry') === (_constants || _load_constants()).YARN_REGISTRY) { - url = url.replace((_constants || _load_constants()).NPM_REGISTRY_RE, (_constants || _load_constants()).YARN_REGISTRY); + yield processMatch(match); } - info._uid = info.version; - info._remote = { - resolved: `${url}#${hash}`, - type: 'tarball', - registry: this.registry, - reference: url, - integrity: info._integrity ? ssri.parse(info._integrity) : ssri.fromHex(hash, 'sha1'), - hash - }; - return info; - } + }); - resolveImport(info) { - var _normalizePattern4 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + return function run(_x4, _x5, _x6, _x7) { + return _ref6.apply(this, arguments); + }; +})(); - const range = _normalizePattern4.range; +exports.setFlags = setFlags; +exports.hasWrapper = hasWrapper; +exports.queryWhy = queryWhy; - const Resolver = (0, (_index || _load_index()).getExoticResolver)(range); - if (Resolver && Resolver.prototype instanceof (_hostedGitResolver || _load_hostedGitResolver()).default) { - return this.resolveHostedGit(info, Resolver); - } else if (Resolver && Resolver === (_gistResolver || _load_gistResolver()).default) { - return this.resolveGist(info, Resolver); - } else if (Resolver && Resolver === (_gitResolver || _load_gitResolver()).default) { - return this.resolveGit(info, Resolver); - } else if (Resolver && Resolver === (_fileResolver || _load_fileResolver()).default) { - return this.resolveFile(info, Resolver); - } - return this.resolveRegistry(info); - } +var _install; - resolveLocation(loc) { - var _this = this; +function _load_install() { + return _install = __webpack_require__(34); +} - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const info = yield _this.config.tryManifest(loc, 'npm', false); - if (!info) { - return null; - } - return _this.resolveImport(info); - })(); - } +var _constants; - resolveFixedVersion(fixedVersionPattern) { - var _this2 = this; +function _load_constants() { + return _constants = __webpack_require__(8); +} - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _normalizePattern5 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(fixedVersionPattern); +var _fs; - const range = _normalizePattern5.range; +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} - const exoticResolver = (0, (_index || _load_index()).getExoticResolver)(range); - const manifest = exoticResolver ? yield _this2.request.findExoticVersionInfo(exoticResolver, range) : yield _this2.request.findVersionOnRegistry(fixedVersionPattern); - return manifest; - })(); - } +var _lockfile; - _resolveFromFixedVersions() { - var _this3 = this; +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); +} - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - invariant(_this3.request instanceof ImportPackageRequest, 'request must be ImportPackageRequest'); +var _errors; - var _normalizePattern6 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(_this3.pattern); +function _load_errors() { + return _errors = __webpack_require__(6); +} - const name = _normalizePattern6.name; +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; } } - invariant(_this3.request.dependencyTree instanceof (_logicalDependencyTree || _load_logicalDependencyTree()).LogicalDependencyTree, 'dependencyTree on request must be LogicalDependencyTree'); - const fixedVersionPattern = _this3.request.dependencyTree.getFixedVersionPattern(name, _this3.request.parentNames); - const info = yield _this3.config.getCache(`import-resolver-${fixedVersionPattern}`, function () { - return _this3.resolveFixedVersion(fixedVersionPattern); - }); - if (info) { - return info; - } - throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('importResolveFailed', name, _this3.getCwd())); - })(); - } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - _resolveFromNodeModules() { - var _this4 = this; +const requireLockfile = exports.requireLockfile = true; - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _normalizePattern7 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(_this4.pattern); +const invariant = __webpack_require__(9); +const bytes = __webpack_require__(564); +const emoji = __webpack_require__(302); +const path = __webpack_require__(0); - const name = _normalizePattern7.name; +function sum(array) { + return array.length ? array.reduce((a, b) => a + b, 0) : 0; +} - let cwd = _this4.getCwd(); - while (!path.relative(_this4.config.cwd, cwd).startsWith('..')) { - const loc = path.join(cwd, 'node_modules', name); - const info = yield _this4.config.getCache(`import-resolver-${loc}`, function () { - return _this4.resolveLocation(loc); - }); - if (info) { - return info; - } - cwd = path.resolve(cwd, '../..'); - } - throw new (_errors || _load_errors()).MessageError(_this4.reporter.lang('importResolveFailed', name, _this4.getCwd())); - })(); - } +function collect(hoistManifests, allDependencies, dependency, { recursive } = { recursive: false }) { + const depInfo = dependency[1]; - resolve() { - if (this.request instanceof ImportPackageRequest && this.request.dependencyTree) { - return this._resolveFromFixedVersions(); - } else { - return this._resolveFromNodeModules(); - } - } -} + const deps = depInfo.pkg.dependencies; -class ImportPackageRequest extends (_packageRequest || _load_packageRequest()).default { - constructor(req, dependencyTree, resolver) { - super(req, resolver); - this.import = this.parentRequest instanceof ImportPackageRequest ? this.parentRequest.import : true; - this.dependencyTree = dependencyTree; + if (!deps) { + return allDependencies; } - getRootName() { - return this.resolver instanceof ImportPackageResolver && this.resolver.rootName || 'root'; - } + const dependencyKeys = new Set(Object.keys(deps)); + const directDependencies = []; - getParentHumanName() { - return [this.getRootName()].concat(this.parentNames).join(' > '); - } + for (var _iterator = hoistManifests, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref3; - reportResolvedRangeMatch(info, resolved) { - if (info.version === resolved.version) { - return; + if (_isArray) { + if (_i >= _iterator.length) break; + _ref3 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref3 = _i.value; } - this.reporter.warn(this.reporter.lang('importResolvedRangeMatch', resolved.version, resolved.name, info.version, this.getParentHumanName())); - } - _findResolvedManifest(info) { - var _normalizePattern8 = (0, (_normalizePattern9 || _load_normalizePattern()).normalizePattern)(this.pattern); + const dep = _ref3; + const info = dep[1]; - const range = _normalizePattern8.range, - name = _normalizePattern8.name; - const solvedRange = (_semver || _load_semver()).default.validRange(range) ? info.version : range; - const resolved = this.resolver.getExactVersionMatch(name, solvedRange, info); - if (resolved) { - return resolved; + if (!allDependencies.has(dep) && dependencyKeys.has(info.key)) { + allDependencies.add(dep); + directDependencies.push(dep); } - invariant(info._remote, 'expected package remote'); - const ref = new (_packageReference || _load_packageReference()).default(this, info, info._remote); - info._reference = ref; - return info; } - resolveToExistingVersion(info) { - const resolved = this._findResolvedManifest(info); - invariant(resolved, 'should have found a resolved reference'); - const ref = resolved._reference; - invariant(ref, 'should have a package reference'); - ref.addRequest(this); - ref.addPattern(this.pattern, resolved); - ref.addOptional(this.optional); + if (recursive) { + directDependencies.forEach(dependency => collect(hoistManifests, allDependencies, dependency, { recursive: true })); } - findVersionInfo() { - if (!this.import) { - this.reporter.verbose(this.reporter.lang('skippingImport', this.pattern, this.getParentHumanName())); - return super.findVersionInfo(); - } - const resolver = new ImportResolver(this, this.pattern); - return resolver.resolve().catch(() => { - this.import = false; - this.reporter.warn(this.reporter.lang('importFailed', this.pattern, this.getParentHumanName())); - return super.findVersionInfo(); - }); - } + return allDependencies; } -class ImportPackageResolver extends (_packageResolver || _load_packageResolver()).default { - constructor(config, lockfile) { - super(config, lockfile); - this.next = []; - this.rootName = 'root'; - } - - find(req) { - this.next.push(req); - return Promise.resolve(); - } - - findOne(req) { - var _this5 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (_this5.activity) { - _this5.activity.tick(req.pattern); - } - const request = new ImportPackageRequest(req, _this5.dependencyTree, _this5); - yield request.find({ fresh: false }); - })(); - } - - findAll(deps) { - var _this6 = this; +function getSharedDependencies(hoistManifests, transitiveKeys) { + const sharedDependencies = new Set(); + for (var _iterator2 = hoistManifests, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref5; - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - yield Promise.all(deps.map(function (dep) { - return _this6.findOne(dep); - })); - deps = _this6.next; - _this6.next = []; - if (!deps.length) { - // all required package versions have been discovered, so now packages that - // resolved to existing versions can be resolved to their best available version - _this6.resolvePackagesWithExistingVersions(); - return; - } - yield _this6.findAll(deps); - })(); - } + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref5 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref5 = _i2.value; + } - resetOptional() { - for (const pattern in this.patterns) { - const ref = this.patterns[pattern]._reference; - invariant(ref, 'expected reference'); - ref.optional = null; - for (var _iterator = ref.requests, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; + const _ref4 = _ref5; + const info = _ref4[1]; - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; + if (!transitiveKeys.has(info.key) && info.pkg.dependencies) { + Object.keys(info.pkg.dependencies).forEach(dependency => { + if (transitiveKeys.has(dependency) && !sharedDependencies.has(dependency)) { + sharedDependencies.add(dependency); } - - const req = _ref; - - ref.addOptional(req.optional); - } + }); } } - - init(deps, { isFlat, isFrozen, workspaceLayout } = { isFlat: false, isFrozen: false, workspaceLayout: undefined }) { - var _this7 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this7.flat = Boolean(isFlat); - const activity = _this7.activity = _this7.reporter.activity(); - yield _this7.findAll(deps); - _this7.resetOptional(); - activity.end(); - _this7.activity = null; - })(); - } + return sharedDependencies; } -class Import extends (_install || _load_install()).Install { - constructor(flags, config, reporter, lockfile) { - super(flags, config, reporter, lockfile); - this.resolver = new ImportPackageResolver(this.config, this.lockfile); - this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); - } - createLogicalDependencyTree(packageJson, packageLock) { - invariant(packageJson, 'package.json should exist'); - invariant(packageLock, 'package-lock.json should exist'); - invariant(this.resolver instanceof ImportPackageResolver, 'resolver should be an ImportPackageResolver'); - try { - this.resolver.dependencyTree = new (_logicalDependencyTree || _load_logicalDependencyTree()).LogicalDependencyTree(packageJson, packageLock); - } catch (e) { - throw new (_errors || _load_errors()).MessageError(this.reporter.lang('importSourceFilesCorrupted')); - } - } - getExternalLockfileContents() { - var _this8 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - try { - var _ref2 = yield Promise.all([(_fs || _load_fs()).readFile(path.join(_this8.config.cwd, (_constants || _load_constants()).NODE_PACKAGE_JSON)), (_fs || _load_fs()).readFile(path.join(_this8.config.cwd, (_constants || _load_constants()).NPM_LOCK_FILENAME))]); +function setFlags(commander) { + commander.description('Identifies why a package has been installed, detailing which other packages depend on it.'); +} - const packageJson = _ref2[0], - packageLock = _ref2[1]; +function hasWrapper(commander, args) { + return true; +} - return { packageJson, packageLock }; - } catch (e) { - return { packageJson: null, packageLock: null }; - } - })(); +// to conform to the current standard '#' as package tree separator +function toStandardPathString(pathString) { + const str = pathString.replace(/\//g, '#'); + if (str[0] === '#') { + return str.slice(1); } - init() { - var _this9 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (yield (_fs || _load_fs()).exists(path.join(_this9.config.cwd, (_constants || _load_constants()).LOCKFILE_FILENAME))) { - throw new (_errors || _load_errors()).MessageError(_this9.reporter.lang('lockfileExists')); - } - - var _ref3 = yield _this9.getExternalLockfileContents(); - - const packageJson = _ref3.packageJson, - packageLock = _ref3.packageLock; + return str; +} - const importSource = packageJson && packageLock && (_semver || _load_semver()).default.satisfies(nodeVersion, '>=5.0.0') ? 'package-lock.json' : 'node_modules'; - if (importSource === 'package-lock.json') { - _this9.reporter.info(_this9.reporter.lang('importPackageLock')); - _this9.createLogicalDependencyTree(packageJson, packageLock); - } - if (importSource === 'node_modules') { - _this9.reporter.info(_this9.reporter.lang('importNodeModules')); - yield (0, (_check || _load_check()).verifyTreeCheck)(_this9.config, _this9.reporter, {}, []); - } +function queryWhy(pattern, hoisted) { + const nohoistPattern = `#${pattern}`; + const found = []; + for (var _iterator6 = hoisted, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref13; - var _ref4 = yield _this9.fetchRequestFromCwd(); + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref13 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref13 = _i6.value; + } - const requests = _ref4.requests, - patterns = _ref4.patterns, - manifest = _ref4.manifest; + const _ref12 = _ref13; + const loc = _ref12[0]; + const info = _ref12[1]; - if (manifest.name && _this9.resolver instanceof ImportPackageResolver) { - _this9.resolver.rootName = manifest.name; - } - yield _this9.resolver.init(requests, { isFlat: _this9.flags.flat, isFrozen: _this9.flags.frozenLockfile }); - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this9.resolver.getManifests(), _this9.config); - _this9.resolver.updateManifests(manifests); - yield (_packageCompatibility || _load_packageCompatibility()).check(_this9.resolver.getManifests(), _this9.config, _this9.flags.ignoreEngines); - yield _this9.linker.resolvePeerModules(); - yield _this9.saveLockfileAndIntegrity(patterns); - return patterns; - })(); + if (info.key === pattern || info.previousPaths.indexOf(pattern) >= 0 || info.key.endsWith(nohoistPattern)) { + found.push([loc, info]); + } } -} - -exports.Import = Import; -function setFlags(commander) { - commander.description('Generates yarn.lock from an npm package-lock.json file or an existing npm-installed node_modules folder.'); -} - -function hasWrapper(commander, args) { - return true; + return found; } /***/ }), -/* 533 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96830,58 +95733,45 @@ function _load_asyncToGenerator() { let run = exports.run = (() => { var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - if (args.length > 2) { - reporter.error(reporter.lang('tooManyArguments', 2)); - return; - } + const workspaceRootFolder = config.workspaceRootFolder; - let packageName = args.shift() || '.'; - // Handle the case when we are referencing a local package. - if (packageName === '.') { - packageName = (yield config.readRootManifest()).name; + if (!workspaceRootFolder) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceRootNotFound', config.cwd)); } - const packageInput = (_npmRegistry || _load_npmRegistry()).default.escapeName(packageName); + if (args.length < 1) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceMissingWorkspace')); + } - var _parsePackageName = (0, (_parsePackageName2 || _load_parsePackageName()).default)(packageInput); + if (args.length < 2) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceMissingCommand')); + } - const name = _parsePackageName.name, - version = _parsePackageName.version; + const manifest = yield config.findManifest(workspaceRootFolder, false); + invariant(manifest && manifest.workspaces, 'We must find a manifest with a "workspaces" property'); + const workspaces = yield config.resolveWorkspaces(workspaceRootFolder, manifest); - let result; - try { - result = yield config.registries.npm.request(name, { unfiltered: true }); - } catch (e) { - reporter.error(reporter.lang('infoFail')); - return; - } - if (!result) { - reporter.error(reporter.lang('infoFail')); - return; - } + var _ref2 = args || []; - result = clean(result); + const workspaceName = _ref2[0], + rest = _ref2.slice(1); - const versions = result.versions; - // $FlowFixMe - result.versions = Object.keys(versions).sort(semver.compareLoose); - result.version = version || result['dist-tags'].latest; - result = Object.assign(result, versions[result.version]); + if (!Object.prototype.hasOwnProperty.call(workspaces, workspaceName)) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceUnknownWorkspace', workspaceName)); + } - const fieldPath = args.shift(); - const fields = fieldPath ? fieldPath.split('.') : []; + const workspace = workspaces[workspaceName]; - // Readmes can be long so exclude them unless explicitly asked for. - if (fields[0] !== 'readme') { - delete result.readme; + try { + yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [(_constants || _load_constants()).YARN_BIN_PATH, ...rest], { + stdio: 'inherit', + cwd: workspace.loc + }); + } catch (err) { + throw err; } - - result = fields.reduce(function (prev, cur) { - return prev && prev[cur]; - }, result); - reporter.inspect(result); }); return function run(_x, _x2, _x3, _x4) { @@ -96892,62 +95782,38 @@ let run = exports.run = (() => { exports.setFlags = setFlags; exports.hasWrapper = hasWrapper; -var _npmRegistry; +var _errors; -function _load_npmRegistry() { - return _npmRegistry = _interopRequireDefault(__webpack_require__(88)); +function _load_errors() { + return _errors = __webpack_require__(6); } -var _parsePackageName2; +var _child; -function _load_parsePackageName() { - return _parsePackageName2 = _interopRequireDefault(__webpack_require__(588)); +function _load_child() { + return _child = _interopRequireWildcard(__webpack_require__(50)); } -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +var _constants; -const semver = __webpack_require__(22); +function _load_constants() { + return _constants = __webpack_require__(8); +} -function clean(object) { - if (Array.isArray(object)) { - const result = []; - object.forEach(item => { - item = clean(item); - if (item) { - result.push(item); - } - }); - return result; - } else if (typeof object === 'object') { - const result = {}; - for (const key in object) { - if (key.startsWith('_')) { - continue; - } +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; } } - const item = clean(object[key]); - if (item) { - result[key] = item; - } - } - return result; - } else if (object) { - return object; - } else { - return null; - } -} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function setFlags(commander) { - commander.description('Shows information about a package.'); -} +const invariant = __webpack_require__(9); + +function setFlags(commander) {} function hasWrapper(commander, args) { return true; } /***/ }), -/* 534 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96956,7 +95822,7 @@ function hasWrapper(commander, args) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.getGitConfigInfo = exports.run = exports.shouldRunInCurrentCwd = undefined; +exports.examples = exports.setFlags = exports.run = exports.runScript = exports.info = undefined; var _asyncToGenerator2; @@ -96964,94 +95830,23 @@ function _load_asyncToGenerator() { return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -let run = exports.run = (() => { +let info = exports.info = (() => { var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - if (flags.install) { - const lockfilePath = path.resolve(config.cwd, 'yarn.lock'); - if (!(yield (_fs || _load_fs()).exists(lockfilePath))) { - yield (_fs || _load_fs()).writeFile(lockfilePath, ''); - } - yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [process.argv[1], 'policies', 'set-version', flags.install], { - stdio: 'inherit', - cwd: config.cwd - }); - yield (_child || _load_child()).spawn((_constants || _load_constants()).NODE_BIN_PATH, [process.argv[1], 'init', ...(flags.yes ? ['-y'] : []), ...(flags.private ? ['-p'] : [])], { - stdio: 'inherit', - cwd: config.cwd - }); - return; - } + const workspaceRootFolder = config.workspaceRootFolder; - const manifests = yield config.getRootManifests(); - let repository = {}; - const author = { - name: config.getOption('init-author-name'), - email: config.getOption('init-author-email'), - url: config.getOption('init-author-url') - }; - if (yield (_fs || _load_fs()).exists(path.join(config.cwd, '.git'))) { - // get git origin of the cwd - try { - repository = { - type: 'git', - url: yield (_child || _load_child()).spawn('git', ['config', 'remote.origin.url'], { - cwd: config.cwd - }) - }; - } catch (ex) { - // Ignore - Git repo may not have an origin URL yet (eg. if it only exists locally) - } + if (!workspaceRootFolder) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceRootNotFound', config.cwd)); + } - if (author.name === undefined) { - author.name = yield getGitConfigInfo('user.name'); - } + const manifest = yield config.findManifest(workspaceRootFolder, false); + invariant(manifest && manifest.workspaces, 'We must find a manifest with a "workspaces" property'); - if (author.email === undefined) { - author.email = yield getGitConfigInfo('user.email'); - } - } + const workspaces = yield config.resolveWorkspaces(workspaceRootFolder, manifest); - const keys = [{ - key: 'name', - question: 'name', - default: path.basename(config.cwd), - validation: (_validate || _load_validate()).isValidPackageName, - validationError: 'invalidPackageName' - }, { - key: 'version', - question: 'version', - default: String(config.getOption('init-version')) - }, { - key: 'description', - question: 'description', - default: '' - }, { - key: 'main', - question: 'entry point', - default: 'index.js' - }, { - key: 'repository', - question: 'repository url', - default: (0, (_util || _load_util()).extractRepositoryUrl)(repository) - }, { - key: 'author', - question: 'author', - default: (0, (_util || _load_util()).stringifyPerson)(author) - }, { - key: 'license', - question: 'license', - default: String(config.getOption('init-license')) - }, { - key: 'private', - question: 'private', - default: config.getOption('init-private') || '', - inputFormatter: yn - }]; + const publicData = {}; - // get answers - const pkg = {}; - for (var _iterator = keys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + for (var _iterator = Object.keys(workspaces), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref2; if (_isArray) { @@ -97063,233 +95858,199 @@ let run = exports.run = (() => { _ref2 = _i.value; } - const entry = _ref2; - const yes = flags.yes, - privateFlag = flags.private; - const manifestKey = entry.key; - let question = entry.question, - def = entry.default; + const workspaceName = _ref2; + var _workspaces$workspace = workspaces[workspaceName]; + const loc = _workspaces$workspace.loc, + manifest = _workspaces$workspace.manifest; - for (var _iterator4 = (_index || _load_index()).registryNames, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref5; + const workspaceDependencies = new Set(); + const mismatchedWorkspaceDependencies = new Set(); - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref5 = _iterator4[_i4++]; + for (var _iterator2 = (_constants || _load_constants()).DEPENDENCY_TYPES, _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 { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref5 = _i4.value; + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref3 = _i2.value; } - const registryName = _ref5; - const object = manifests[registryName].object; - - let val = objectPath.get(object, manifestKey); - if (!val) { - break; - } - if (typeof val === 'object') { - if (manifestKey === 'author') { - val = (0, (_util || _load_util()).stringifyPerson)(val); - } else if (manifestKey === 'repository') { - val = (0, (_util || _load_util()).extractRepositoryUrl)(val); - } - } - def = val; - } + const dependencyType = _ref3; - if (manifestKey === 'private' && privateFlag) { - def = true; - } + if (dependencyType !== 'peerDependencies') { + for (var _iterator3 = Object.keys(manifest[dependencyType] || {}), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref4; - if (def) { - question += ` (${String(def)})`; - } + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref4 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref4 = _i3.value; + } - let answer; - let validAnswer = false; + const dependencyName = _ref4; - if (yes) { - answer = def; - } else { - // loop until a valid answer is provided, if validation is on entry - if (entry.validation) { - while (!validAnswer) { - answer = (yield reporter.question(question)) || def; - // validate answer - if (entry.validation(String(answer))) { - validAnswer = true; - } else { - reporter.error(reporter.lang('invalidPackageName')); + if (Object.prototype.hasOwnProperty.call(workspaces, dependencyName)) { + invariant(manifest && manifest[dependencyType], 'The request should exist'); + const requestedRange = manifest[dependencyType][dependencyName]; + if (semver.satisfies(workspaces[dependencyName].manifest.version, requestedRange)) { + workspaceDependencies.add(dependencyName); + } else { + mismatchedWorkspaceDependencies.add(dependencyName); + } } } - } else { - answer = (yield reporter.question(question)) || def; } } - if (answer) { - if (entry.inputFormatter) { - answer = entry.inputFormatter(answer); - } - objectPath.set(pkg, manifestKey, answer); - } + publicData[workspaceName] = { + location: path.relative(config.lockfileFolder, loc).replace(/\\/g, '/'), + workspaceDependencies: Array.from(workspaceDependencies), + mismatchedWorkspaceDependencies: Array.from(mismatchedWorkspaceDependencies) + }; } - if (pkg.repository && (_githubResolver || _load_githubResolver()).default.isVersion(pkg.repository)) { - pkg.repository = `https://github.com/${pkg.repository}`; - } + reporter.log(JSON.stringify(publicData, null, 2), { force: true }); + }); - // save answers - const targetManifests = []; - for (var _iterator2 = (_index || _load_index()).registryNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref3; + return function info(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref3 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref3 = _i2.value; - } +let runScript = exports.runScript = (() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + const workspaceRootFolder = config.workspaceRootFolder; - const registryName = _ref3; - const info = manifests[registryName]; - if (info.exists) { - targetManifests.push(info); - } - } - if (!targetManifests.length) { - targetManifests.push(manifests.npm); + if (!workspaceRootFolder) { + throw new (_errors || _load_errors()).MessageError(reporter.lang('workspaceRootNotFound', config.cwd)); } - for (var _iterator3 = targetManifests, _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 manifest = yield config.findManifest(workspaceRootFolder, false); + invariant(manifest && manifest.workspaces, 'We must find a manifest with a "workspaces" property'); - const targetManifest = _ref4; + const workspaces = yield config.resolveWorkspaces(workspaceRootFolder, manifest); - Object.assign(targetManifest.object, pkg); - reporter.success(`Saved ${path.basename(targetManifest.loc)}`); - } + try { + for (var _iterator4 = Object.keys(workspaces), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref6; - yield config.saveRootManifests(manifests); + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref6 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref6 = _i4.value; + } + + const workspaceName = _ref6; + const loc = workspaces[workspaceName].loc; + + reporter.log(`${os.EOL}> ${workspaceName}`); + yield (_child || _load_child()).spawn((_constants2 || _load_constants2()).NODE_BIN_PATH, [(_constants2 || _load_constants2()).YARN_BIN_PATH, 'run', ...args], { + stdio: 'inherit', + cwd: loc + }); + } + } catch (err) { + throw err; + } }); - return function run(_x, _x2, _x3, _x4) { - return _ref.apply(this, arguments); + return function runScript(_x5, _x6, _x7, _x8) { + return _ref5.apply(this, arguments); }; })(); -let getGitConfigInfo = exports.getGitConfigInfo = (() => { - var _ref6 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (credential, spawn = (_child || _load_child()).spawn) { - try { - // try to get author default based on git config - return yield spawn('git', ['config', credential]); - } catch (e) { - return ''; - } - }); - - return function getGitConfigInfo(_x5) { - return _ref6.apply(this, arguments); - }; -})(); - -exports.setFlags = setFlags; exports.hasWrapper = hasWrapper; -var _util; +var _errors; -function _load_util() { - return _util = __webpack_require__(221); +function _load_errors() { + return _errors = __webpack_require__(6); } -var _index; +var _buildSubCommands2; -function _load_index() { - return _index = __webpack_require__(57); +function _load_buildSubCommands() { + return _buildSubCommands2 = _interopRequireDefault(__webpack_require__(59)); } -var _githubResolver; +var _constants; -function _load_githubResolver() { - return _githubResolver = _interopRequireDefault(__webpack_require__(367)); +function _load_constants() { + return _constants = __webpack_require__(8); } var _child; function _load_child() { - return _child = _interopRequireWildcard(__webpack_require__(58)); -} - -var _fs; - -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(4)); -} - -var _validate; - -function _load_validate() { - return _validate = _interopRequireWildcard(__webpack_require__(125)); + return _child = _interopRequireWildcard(__webpack_require__(50)); } -var _constants; +var _constants2; -function _load_constants() { - return _constants = __webpack_require__(8); +function _load_constants2() { + return _constants2 = __webpack_require__(8); } 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 objectPath = __webpack_require__(304); - +const invariant = __webpack_require__(9); const path = __webpack_require__(0); -const yn = __webpack_require__(962); - -function setFlags(commander) { - commander.description('Interactively creates or updates a package.json file.'); - commander.option('-y, --yes', 'use default options'); - commander.option('-p, --private', 'use default options and private true'); - commander.option('-i, --install ', 'install a specific Yarn release'); -} +const os = __webpack_require__(46); +const semver = __webpack_require__(22); function hasWrapper(commander, args) { return true; } -const shouldRunInCurrentCwd = exports.shouldRunInCurrentCwd = true; +var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).default)('workspaces', { + info(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + yield info(config, reporter, flags, args); + })(); + }, + run(config, reporter, flags, args) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + yield runScript(config, reporter, flags, args); + })(); + } +}); + +const run = _buildSubCommands.run, + setFlags = _buildSubCommands.setFlags, + examples = _buildSubCommands.examples; +exports.run = run; +exports.setFlags = setFlags; +exports.examples = examples; /***/ }), -/* 535 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(module) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.examples = exports.run = undefined; +exports.autoRun = exports.main = undefined; var _extends2; function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(21)); + return _extends2 = _interopRequireDefault(__webpack_require__(20)); } var _asyncToGenerator2; @@ -97298,830 +96059,875 @@ function _load_asyncToGenerator() { return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); } -let getManifests = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags) { - const lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.cwd); - const install = new (_install || _load_install()).Install((0, (_extends2 || _load_extends()).default)({ skipIntegrityCheck: true }, flags), config, new (_baseReporter || _load_baseReporter()).default(), lockfile); - yield install.hydrate(true); +let main = exports.main = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* ({ + startArgs, + args, + endArgs + }) { + const collect = function collect(val, acc) { + acc.push(val); + return acc; + }; - let manifests = install.resolver.getManifests(); + (0, (_loudRejection || _load_loudRejection()).default)(); + (0, (_signalHandler || _load_signalHandler()).default)(); - // sort by name - manifests = manifests.sort(function (a, b) { - if (!a.name && !b.name) { - return 0; - } + // set global options + (_commander || _load_commander()).default.version((_yarnVersion || _load_yarnVersion()).version, '-v, --version'); + (_commander || _load_commander()).default.usage('[command] [flags]'); + (_commander || _load_commander()).default.option('--no-default-rc', 'prevent Yarn from automatically detecting yarnrc and npmrc files'); + (_commander || _load_commander()).default.option('--use-yarnrc ', 'specifies a yarnrc file that Yarn should use (.yarnrc only, not .npmrc)', collect, []); + (_commander || _load_commander()).default.option('--verbose', 'output verbose messages on internal operations'); + (_commander || _load_commander()).default.option('--offline', 'trigger an error if any required dependencies are not available in local cache'); + (_commander || _load_commander()).default.option('--prefer-offline', 'use network only if dependencies are not available in local cache'); + (_commander || _load_commander()).default.option('--enable-pnp, --pnp', "enable the Plug'n'Play installation"); + (_commander || _load_commander()).default.option('--disable-pnp', "disable the Plug'n'Play installation"); + (_commander || _load_commander()).default.option('--strict-semver'); + (_commander || _load_commander()).default.option('--json', 'format Yarn log messages as lines of JSON (see jsonlines.org)'); + (_commander || _load_commander()).default.option('--ignore-scripts', "don't run lifecycle scripts"); + (_commander || _load_commander()).default.option('--har', 'save HAR output of network traffic'); + (_commander || _load_commander()).default.option('--ignore-platform', 'ignore platform checks'); + (_commander || _load_commander()).default.option('--ignore-engines', 'ignore engines check'); + (_commander || _load_commander()).default.option('--ignore-optional', 'ignore optional dependencies'); + (_commander || _load_commander()).default.option('--force', 'install and build packages even if they were built before, overwrite lockfile'); + (_commander || _load_commander()).default.option('--skip-integrity-check', 'run install without checking if node_modules is installed'); + (_commander || _load_commander()).default.option('--check-files', 'install will verify file tree of packages for consistency'); + (_commander || _load_commander()).default.option('--no-bin-links', "don't generate bin links when setting up packages"); + (_commander || _load_commander()).default.option('--flat', 'only allow one version of a package'); + (_commander || _load_commander()).default.option('--prod, --production [prod]', '', (_conversion || _load_conversion()).boolify); + (_commander || _load_commander()).default.option('--no-lockfile', "don't read or generate a lockfile"); + (_commander || _load_commander()).default.option('--pure-lockfile', "don't generate a lockfile"); + (_commander || _load_commander()).default.option('--frozen-lockfile', "don't generate a lockfile and fail if an update is needed"); + (_commander || _load_commander()).default.option('--update-checksums', 'update package checksums from current repository'); + (_commander || _load_commander()).default.option('--link-duplicates', 'create hardlinks to the repeated modules in node_modules'); + (_commander || _load_commander()).default.option('--link-folder ', 'specify a custom folder to store global links'); + (_commander || _load_commander()).default.option('--global-folder ', 'specify a custom folder to store global packages'); + (_commander || _load_commander()).default.option('--modules-folder ', 'rather than installing modules into the node_modules folder relative to the cwd, output them here'); + (_commander || _load_commander()).default.option('--preferred-cache-folder ', 'specify a custom folder to store the yarn cache if possible'); + (_commander || _load_commander()).default.option('--cache-folder ', 'specify a custom folder that must be used to store the yarn cache'); + (_commander || _load_commander()).default.option('--mutex [:specifier]', 'use a mutex to ensure only one yarn instance is executing'); + (_commander || _load_commander()).default.option('--emoji [bool]', 'enable emoji in output', (_conversion || _load_conversion()).boolify, process.platform === 'darwin' || process.env.TERM_PROGRAM === 'Hyper' || process.env.TERM_PROGRAM === 'HyperTerm' || process.env.TERM_PROGRAM === 'Terminus'); + (_commander || _load_commander()).default.option('-s, --silent', 'skip Yarn console logs, other types of logs (script output) will be printed'); + (_commander || _load_commander()).default.option('--cwd ', 'working directory to use', process.cwd()); + (_commander || _load_commander()).default.option('--proxy ', ''); + (_commander || _load_commander()).default.option('--https-proxy ', ''); + (_commander || _load_commander()).default.option('--registry ', 'override configuration registry'); + (_commander || _load_commander()).default.option('--no-progress', 'disable progress bar'); + (_commander || _load_commander()).default.option('--network-concurrency ', 'maximum number of concurrent network requests', parseInt); + (_commander || _load_commander()).default.option('--network-timeout ', 'TCP timeout for network requests', parseInt); + (_commander || _load_commander()).default.option('--non-interactive', 'do not show interactive prompts'); + (_commander || _load_commander()).default.option('--scripts-prepend-node-path [bool]', 'prepend the node executable dir to the PATH in scripts', (_conversion || _load_conversion()).boolify); + (_commander || _load_commander()).default.option('--no-node-version-check', 'do not warn when using a potentially unsupported Node version'); + (_commander || _load_commander()).default.option('--focus', 'Focus on a single workspace by installing remote copies of its sibling workspaces.'); + (_commander || _load_commander()).default.option('--otp ', 'one-time password for two factor authentication'); - if (!a.name) { - return 1; - } + // if -v is the first command, then always exit after returning the version + if (args[0] === '-v') { + console.log((_yarnVersion || _load_yarnVersion()).version.trim()); + process.exitCode = 0; + return; + } - if (!b.name) { - return -1; - } + // get command name + const firstNonFlagIndex = args.findIndex(function (arg, idx, arr) { + const isOption = arg.startsWith('-'); + const prev = idx > 0 && arr[idx - 1]; + const prevOption = prev && prev.startsWith('-') && (_commander || _load_commander()).default.optionFor(prev); + const boundToPrevOption = prevOption && (prevOption.optional || prevOption.required); - return a.name.localeCompare(b.name); + return !isOption && !boundToPrevOption; }); + let preCommandArgs; + let commandName = ''; + if (firstNonFlagIndex > -1) { + preCommandArgs = args.slice(0, firstNonFlagIndex); + commandName = args[firstNonFlagIndex]; + args = args.slice(firstNonFlagIndex + 1); + } else { + preCommandArgs = args; + args = []; + } - // filter ignored manifests - manifests = manifests.filter(function (manifest) { - const ref = manifest._reference; - return !!ref && !ref.ignore; - }); + let isKnownCommand = Object.prototype.hasOwnProperty.call((_index3 || _load_index3()).default, commandName); + const isHelp = function isHelp(arg) { + return arg === '--help' || arg === '-h'; + }; + const helpInPre = preCommandArgs.findIndex(isHelp); + const helpInArgs = args.findIndex(isHelp); + const setHelpMode = function setHelpMode() { + if (isKnownCommand) { + args.unshift(commandName); + } + commandName = 'help'; + isKnownCommand = true; + }; - return manifests; - }); + if (helpInPre > -1) { + preCommandArgs.splice(helpInPre); + setHelpMode(); + } else if (isKnownCommand && helpInArgs === 0) { + args.splice(helpInArgs); + setHelpMode(); + } - return function getManifests(_x, _x2) { - return _ref.apply(this, arguments); - }; -})(); + if (!commandName) { + commandName = 'install'; + isKnownCommand = true; + } + if (commandName === 'set' && args[0] === 'version') { + commandName = 'policies'; + args.splice(0, 1, 'set-version'); + isKnownCommand = true; + } + if (!isKnownCommand) { + // if command is not recognized, then set default to `run` + args.unshift(commandName); + commandName = 'run'; + } + const command = (_index3 || _load_index3()).default[commandName]; -let list = (() => { - var _ref2 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - const manifests = yield getManifests(config, flags); - const manifestsByLicense = new Map(); + let warnAboutRunDashDash = false; + // we are using "yarn diff --git a/packages/extensionmanager-extension/examples/listings/webpack.config.js b/packages/extensionmanager-extension/examples/listings/webpack.config.js index ca27005..cbc53b5 100644 --- a/packages/extensionmanager-extension/examples/listings/webpack.config.js +++ b/packages/extensionmanager-extension/examples/listings/webpack.config.js @@ -1,14 +1,15 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -var data = require('./package.json'); -var Build = require('@jupyterlab/builder').Build; +const data = require('./package.json'); +const Build = require('@jupyterlab/builder').Build; +const miniSVGDataURI = require('mini-svg-data-uri'); -var names = Object.keys(data.dependencies).filter(function (name) { - var packageData = require(name + '/package.json'); +const names = Object.keys(data.dependencies).filter(function (name) { + const packageData = require(name + '/package.json'); return packageData.jupyterlab !== undefined; }); -var extras = Build.ensureAssets({ +const extras = Build.ensureAssets({ packageNames: names, output: './build' }); @@ -29,30 +30,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', + generator: { + dataUrl: content => miniSVGDataURI(content.toString()) } }, { @@ -60,9 +61,7 @@ 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/resource' } ] } diff --git a/packages/extensionmanager-extension/package.json b/packages/extensionmanager-extension/package.json index a9911bb..008b737 100644 --- a/packages/extensionmanager-extension/package.json +++ b/packages/extensionmanager-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/extensionmanager-extension", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Extension Manager Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -38,17 +38,17 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/extensionmanager": "^3.3.2", - "@jupyterlab/settingregistry": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2" + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/extensionmanager": "^4.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/extensionmanager-extension/schema/plugin.json b/packages/extensionmanager-extension/schema/plugin.json index 9e26dfe..031fb12 100644 --- a/packages/extensionmanager-extension/schema/plugin.json +++ b/packages/extensionmanager-extension/schema/plugin.json @@ -1 +1,77 @@ -{} \ No newline at end of file +{ + "title": "Extension Manager", + "description": "Extension manager settings.", + "jupyter.lab.setting-icon": "ui-components:settings", + "jupyter.lab.setting-icon-label": "Extension Manager", + "jupyter.lab.menus": { + "main": [ + { + "id": "jp-mainmenu-view", + "items": [ + { + "command": "extensionmanager:show-panel", + "rank": 9 + } + ] + }, + { + "id": "jp-mainmenu-settings", + "items": [ + { + "type": "separator", + "rank": 100 + }, + { + "command": "extensionmanager:toggle", + "rank": 100 + }, + { + "type": "separator", + "rank": 100 + } + ] + } + ] + }, + "jupyter.lab.shortcuts": [ + { + "command": "extensionmanager:show-panel", + "keys": ["Accel Shift X"], + "selector": "body" + } + ], + "properties": { + "enabled": { + "title": "Enabled Status", + "description": "Enables extension manager (requires Node.js/npm).\nWARNING: installing untrusted extensions may be unsafe.", + "default": true, + "type": "boolean" + }, + "disclaimed": { + "title": "Disclaimed Status", + "description": "Whether the user understand that extensions managed through this interface run arbitrary code that may be dangerous", + "default": false, + "type": "boolean" + }, + "npmRegistry": { + "title": "NPM Registry", + "description": "The URI of the NPM registry to use for searching for jupyterlab extensions", + "default": "https://registry.npmjs.org/-/v1/", + "type": "string" + }, + "npmCdn": { + "title": "NPM CDN", + "description": "The URI of the CDN to use for fetching full package data", + "default": "https://unpkg.com/", + "type": "string" + }, + "enableCdn": { + "title": "Enable CDN", + "description": "Enables using the CDN to fetch full package data. Otherwise, the configured NPM registry will be used. Due to a lack of CORS support by NPM registry, only disable if supplying a custom registry", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false, + "type": "object" +} diff --git a/packages/extensionmanager-extension/src/index.ts b/packages/extensionmanager-extension/src/index.ts index d1cd5f3..5a2482d 100644 --- a/packages/extensionmanager-extension/src/index.ts +++ b/packages/extensionmanager-extension/src/index.ts @@ -23,6 +23,7 @@ const PLUGIN_ID = '@jupyterlab/extensionmanager-extension:plugin'; * IDs of the commands added by this extension. */ namespace CommandIDs { + export const showPanel = 'extensionmanager:show-panel'; export const toggle = 'extensionmanager:toggle'; } @@ -67,7 +68,7 @@ const plugin: JupyterFrontEndPlugin = { 'aria-label', trans.__('Extension Manager section') ); - labShell.add(view, 'left', { rank: 1000 }); + labShell.add(view, 'left', { rank: 1000, type: 'Extension Manager' }); } // If the extension is enabled or disabled, @@ -89,7 +90,10 @@ const plugin: JupyterFrontEndPlugin = { trans.__('Extension Manager section') ); if (labShell) { - labShell.add(view, 'left', { rank: 1000 }); + labShell.add(view, 'left', { + rank: 1000, + type: 'Extension Manager' + }); } } else if (!enabled && view?.isAttached) { app.commands.notifyCommandChanged(CommandIDs.toggle); @@ -103,6 +107,16 @@ const plugin: JupyterFrontEndPlugin = { ); }); + commands.addCommand(CommandIDs.showPanel, { + label: trans.__('Extension Manager'), + execute: () => { + if (view) { + labShell?.activateById(view.id); + } + }, + isVisible: () => enabled && labShell !== null + }); + commands.addCommand(CommandIDs.toggle, { label: trans.__('Enable Extension Manager'), execute: () => { @@ -141,8 +155,8 @@ namespace Private { ): Promise { return showDialog({ title: trans.__('Enable Extension Manager?'), - body: trans.__(`Thanks for trying out Notebook's extension manager. -The Notebook development team is excited to have a robust + body: trans.__(`Thanks for trying out JupyterLab's extension manager. +The JupyterLab development team is excited to have a robust third-party extension community. However, we cannot vouch for every extension, and some may introduce security risks. diff --git a/packages/extensionmanager/package.json b/packages/extensionmanager/package.json index aec67fd..2b418e6 100644 --- a/packages/extensionmanager/package.json +++ b/packages/extensionmanager/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/extensionmanager", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Extension Manager", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -36,26 +36,27 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/settingregistry": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/messaging": "^1.4.3", - "@lumino/polling": "^1.3.3", - "@lumino/signaling": "^1.4.3", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/messaging": "^1.10.1", + "@lumino/polling": "^1.10.0", + "@lumino/signaling": "^1.10.1", "react": "^17.0.1", "react-paginate": "^6.3.2", "semver": "^7.3.2" }, "devDependencies": { + "@types/react": "^17.0.0", "@types/react-paginate": "^6.2.1", "@types/semver": "^7.3.3", "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/extensionmanager/src/companions.tsx b/packages/extensionmanager/src/companions.tsx index d6c53cd..cf54fda 100644 --- a/packages/extensionmanager/src/companions.tsx +++ b/packages/extensionmanager/src/companions.tsx @@ -213,7 +213,7 @@ installation?`)} title, body, buttons: [ - Dialog.cancelButton({ label: trans.__('Cancel') }), + Dialog.cancelButton(), Dialog.okButton({ label: trans.__('OK'), caption: trans.__('Install the JupyterLab extension.') diff --git a/packages/extensionmanager/src/dialog.tsx b/packages/extensionmanager/src/dialog.tsx index 8f68c9c..fe4ee13 100644 --- a/packages/extensionmanager/src/dialog.tsx +++ b/packages/extensionmanager/src/dialog.tsx @@ -15,7 +15,7 @@ export function reportInstallError( name: string, errorMessage?: string, translator?: ITranslator -) { +): void { translator = translator || nullTranslator; const trans = translator.load('jupyterlab'); const entries = []; @@ -36,6 +36,6 @@ export function reportInstallError( void showDialog({ title: trans.__('Extension Installation Error'), body, - buttons: [Dialog.warnButton({ label: trans.__('OK') })] + buttons: [Dialog.warnButton({ label: trans.__('Ok') })] }); } diff --git a/packages/extensionmanager/src/model.ts b/packages/extensionmanager/src/model.ts index def8971..c739d41 100644 --- a/packages/extensionmanager/src/model.ts +++ b/packages/extensionmanager/src/model.ts @@ -2,7 +2,6 @@ // Distributed under the terms of the Modified BSD License. import { JupyterFrontEnd } from '@jupyterlab/application'; -import { VDomModel } from '@jupyterlab/apputils'; import { KernelSpec, ServerConnection, @@ -10,6 +9,7 @@ import { } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { VDomModel } from '@jupyterlab/ui-components'; import { Debouncer } from '@lumino/polling'; import * as semver from 'semver'; import { doBuild } from './build-helper'; @@ -209,7 +209,7 @@ export type Action = 'install' | 'uninstall' | 'enable' | 'disable'; export class ListModel extends VDomModel { constructor( app: JupyterFrontEnd, - serviceManager: ServiceManager, + serviceManager: ServiceManager.IManager, settings: ISettingRegistry.ISettings, translator?: ITranslator ) { @@ -357,6 +357,17 @@ export class ListModel extends VDomModel { return this._totalallowedExtensionsFound; } + /** + * Dispose the extensions list model. + */ + dispose(): void { + if (this.isDisposed) { + return; + } + this._debouncedUpdate.dispose(); + super.dispose(); + } + /** * Initialize the model. */ @@ -744,7 +755,7 @@ export class ListModel extends VDomModel { * * Emits the `stateChanged` signal on successful completion. */ - protected async update(refreshInstalled = false) { + protected async update(refreshInstalled = false): Promise { if (ListModel.isDisclaimed()) { const [searchMap, installedMap] = await Promise.all([ this.performSearch(), @@ -887,7 +898,7 @@ export class ListModel extends VDomModel { /** * The service manager to use for building. */ - protected serviceManager: ServiceManager; + protected serviceManager: ServiceManager.IManager; protected translator: ITranslator; private _app: JupyterFrontEnd; @@ -926,11 +937,11 @@ export namespace ListModel { return semver.lt(entry.installed_version, entry.latest_version); } - export function isDisclaimed() { + export function isDisclaimed(): boolean { return _isDisclaimed; } - export function toogleDisclaimed() { + export function toogleDisclaimed(): void { _isDisclaimed = !_isDisclaimed; } } diff --git a/packages/extensionmanager/src/widget.tsx b/packages/extensionmanager/src/widget.tsx index 6a1a213..ceb914f 100644 --- a/packages/extensionmanager/src/widget.tsx +++ b/packages/extensionmanager/src/widget.tsx @@ -2,12 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { JupyterFrontEnd } from '@jupyterlab/application'; -import { - Dialog, - showDialog, - ToolbarButtonComponent, - VDomRenderer -} from '@jupyterlab/apputils'; +import { Dialog, showDialog } from '@jupyterlab/apputils'; import { ServiceManager } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { @@ -23,7 +18,8 @@ import { InputGroup, jupyterIcon, listingsInfoIcon, - refreshIcon + ToolbarButtonComponent, + VDomRenderer } from '@jupyterlab/ui-components'; import { Message } from '@lumino/messaging'; import * as React from 'react'; @@ -84,7 +80,7 @@ export class SearchBar extends React.Component< /** * Handler for search input changes. */ - handleChange = (e: React.FormEvent) => { + handleChange = (e: React.FormEvent): void => { const target = e.target as HTMLInputElement; this.setState({ value: target.value @@ -250,7 +246,7 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement { )} onClick={() => window.open( - 'https://jupyterlab.readthedocs.io/en/3.3.x/user/extensions.html' + 'https://jupyterlab.readthedocs.io/en/latest/user/extensions.html' ) } /> @@ -266,7 +262,7 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement { )} onClick={() => window.open( - 'https://jupyterlab.readthedocs.io/en/3.3.x/user/extensions.html' + 'https://jupyterlab.readthedocs.io/en/latest/user/extensions.html' ) } /> @@ -285,42 +281,7 @@ function ListEntry(props: ListEntry.IProperties): React.ReactElement { {entry.description}
    - {!entry.installed && - entry.pkg_type == 'source' && - !entry.blockedExtensionsEntry && - !(!entry.allowedExtensionsEntry && listMode === 'allow') && - ListModel.isDisclaimed() && ( - - )} - {ListModel.entryHasUpdate(entry) && - entry.pkg_type == 'source' && - !entry.blockedExtensionsEntry && - !(!entry.allowedExtensionsEntry && listMode === 'allow') && - ListModel.isDisclaimed() && ( - - )} - {entry.installed && entry.pkg_type == 'source' && ( - - )} - {entry.enabled && entry.pkg_type == 'source' && ( + {entry.enabled && ( )} - {entry.installed && entry.pkg_type == 'source' && !entry.enabled && ( + {entry.installed && !entry.enabled && (
    @@ -598,7 +559,7 @@ export class CollapsibleSection extends React.Component< /** * Handler for search input changes. */ - handleCollapse() { + handleCollapse(): void { this.setState( { isOpen: !this.state.isOpen @@ -611,7 +572,9 @@ export class CollapsibleSection extends React.Component< ); } - UNSAFE_componentWillReceiveProps(nextProps: CollapsibleSection.IProperties) { + UNSAFE_componentWillReceiveProps( + nextProps: CollapsibleSection.IProperties + ): void { if (nextProps.forceOpen) { this.setState({ isOpen: true @@ -683,10 +646,9 @@ export class ExtensionView extends VDomRenderer { protected translator: ITranslator; private _trans: TranslationBundle; private _settings: ISettingRegistry.ISettings; - private _forceOpen: boolean; constructor( app: JupyterFrontEnd, - serviceManager: ServiceManager, + serviceManager: ServiceManager.IManager, settings: ISettingRegistry.ISettings, translator?: ITranslator ) { @@ -694,7 +656,6 @@ export class ExtensionView extends VDomRenderer { this.translator = translator || nullTranslator; this._trans = this.translator.load('jupyterlab'); this._settings = settings; - this._forceOpen = false; this.addClass('jp-extensionmanager-view'); } @@ -725,7 +686,7 @@ administrator to verify the listings configuration.`)} ]; } - const pages = Math.ceil(model.totalEntries / model.pagination); const elements = [ {this._trans .__(`The notebook development team is excited to have a robust -third-party extension community. However, we do not review -third-party extensions, and some extensions may introduce security -risks or contain malicious code that runs on your machine.`)} + third-party extension community. However, we do not review + third-party extensions, and some extensions may introduce security + risks or contain malicious code that runs on your machine.`)}
    - {ListModel.isDisclaimed() && ( - - )} - {!ListModel.isDisclaimed() && ( - - )} +
    @@ -863,18 +804,15 @@ risks or contain malicious code that runs on your machine.`)} ); } else { + const query = new RegExp(model.query?.toLowerCase() ?? ''); installedContent.push( 0 - ? model.installed.filter( - entry => model.searchResult.indexOf(entry) > -1 - ) - : model.installed - } + entries={model.installed.filter( + pkg => !model.query || query.test(pkg.name) + )} numPages={1} translator={this.translator} onPage={value => { @@ -885,77 +823,77 @@ risks or contain malicious code that runs on your machine.`)} ); } - content.push( - { - model.refreshInstalled(); - }} - tooltip={this._trans.__('Refresh extension list')} - /> - } - > - {installedContent} - - ); - - const searchContent = []; - if (model.searchError !== null) { - searchContent.push( - - {`Error searching for extensions${ - model.searchError ? `: ${model.searchError}` : '.' - }`} - - ); - } else { - searchContent.push( - model.installed.indexOf(entry) === -1 - )} - numPages={pages} - onPage={value => { - this.onPage(value); - }} - performAction={this.onAction.bind(this)} - translator={this.translator} - /> - ); - } - - content.push( - { - if (isOpen && model.query === null) { - model.query = ''; - } - }} - > - {searchContent} - - ); + // content.push( + // { + // model.refreshInstalled(); + // }} + // tooltip={this._trans.__('Refresh extension list')} + // /> + // } + // > + // {installedContent} + // + // ); + // + // const searchContent = []; + // if (model.searchError !== null) { + // searchContent.push( + // + // {`Error searching for extensions${ + // model.searchError ? `: ${model.searchError}` : '.' + // }`} + // + // ); + // } else { + // searchContent.push( + // model.installed.indexOf(entry) === -1 + // )} + // numPages={pages} + // onPage={value => { + // this.onPage(value); + // }} + // performAction={this.onAction.bind(this)} + // translator={this.translator} + // /> + // ); + // } + // + // content.push( + // { + // if (isOpen && model.query === null) { + // model.query = ''; + // } + // }} + // > + // {searchContent} + // + // ); } elements.push( @@ -964,9 +902,6 @@ risks or contain malicious code that runs on your machine.`)} ); - // Reset the force open for future usage. - this._forceOpen = false; - return elements; } @@ -975,7 +910,7 @@ risks or contain malicious code that runs on your machine.`)} * * @param value The new query. */ - onSearch(value: string) { + onSearch(value: string): void { this.model!.query = value; } @@ -984,7 +919,7 @@ risks or contain malicious code that runs on your machine.`)} * * @param value The pagination page number. */ - onPage(value: number) { + onPage(value: number): void { this.model!.page = value; } @@ -994,7 +929,7 @@ risks or contain malicious code that runs on your machine.`)} * @param action The action to perform. * @param entry The entry to perform the action on. */ - onAction(action: Action, entry: IEntry) { + onAction(action: Action, entry: IEntry): Promise { switch (action) { case 'install': return this.model!.install(entry); diff --git a/packages/extensionmanager/style/base.css b/packages/extensionmanager/style/base.css index f68d9a2..65ae9bd 100644 --- a/packages/extensionmanager/style/base.css +++ b/packages/extensionmanager/style/base.css @@ -1,9 +1,14 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + /* Main widget layout and styling */ .jp-extensionmanager-view { - padding-bottom: 0px; + padding-bottom: 0; color: var(--jp-ui-font-color1); background: var(--jp-layout-color1); display: flex; @@ -32,7 +37,6 @@ .jp-extensionmanager-listview-wrapper { margin: 0; padding: 0; - padding-bottom: 8px; display: flex; flex-direction: column; flex: 0 0 auto; @@ -53,8 +57,7 @@ display: flex; justify-content: space-between; flex: 0 0 auto; - margin: 0px; - padding-bottom: 8px; + margin: 0; font-weight: 600; text-transform: uppercase; border-bottom: var(--jp-border-width) solid var(--jp-border-color2); @@ -66,7 +69,7 @@ } .jp-extensionmanager-view .jp-stack-panel-header > .jp-ToolbarButtonComponent { - padding: 0px 2px; + padding: 0 2px; border: 1px solid transparent; background-color: var(--jp-layout-color1); color: var(--jp-ui-font-color1); @@ -76,29 +79,17 @@ .jp-stack-panel-header .jp-extensionmanager-headerText { flex: 1 0 auto; - margin: 0px 4px; + margin: 0 4px; } .jp-extensionmanager-view .jp-stack-panel-header .jp-extensionmanager-headerTextDisabled { flex: 1 0 auto; - margin: 0px 4px; + margin: 0 4px; color: var(--jp-layout-color3); } -.jp-extensionmanager-view .jp-stack-panel-header > .jp-ToolbarButtonComponent { - border: 1px solid transparent; - background-color: var(--jp-layout-color1); - color: var(--jp-ui-font-color1); -} - -.jp-extensionmanager-view - .jp-stack-panel-header - > .jp-ToolbarButtonComponent:hover { - /* border: 1px solid var(--jp-brand-color1); */ -} - /* Listing messages */ @@ -154,8 +145,8 @@ .jp-extensionmanager-view ul.pagination { display: inline-block; - padding-left: 0px; - padding-right: 0px; + padding-left: 0; + padding-right: 0; } .jp-extensionmanager-view .pagination li { @@ -225,8 +216,10 @@ padding-left: 4px; } -.jp-extensionmanager-entry.jp-extensionmanager-entry-warning { -} +/* this is not styled */ + +/* .jp-extensionmanager-entry.jp-extensionmanager-entry-warning { +} */ .jp-extensionmanager-entry-name { font-size: var(--jp-ui-font-size1); @@ -251,12 +244,6 @@ text-decoration: underline; } -.jp-extensionmanager-entry-description { - font-size: var(--jp-ui-font-size1); - color: var(--jp-ui-font-color2); - font-weight: 400; -} - .jp-extensionmanager-loader, .jp-extensionmanager-error, .jp-extensionmanager-listview-message { @@ -286,7 +273,7 @@ background-color: var(--jp-layout-color1); } -.jp-extensionmanager-pending.jp-mod-hasPending:before { +.jp-extensionmanager-pending.jp-mod-hasPending::before { display: block; position: absolute; content: ''; @@ -303,18 +290,23 @@ left: -200px; width: 30%; } + 50% { width: 30%; } + 70% { width: 70%; } + 80% { left: 50%; } + 95% { left: 120%; } + to { left: 100%; } @@ -327,14 +319,14 @@ .jp-extensionmanager-disclaimer-disable { background-color: var(--jp-brand-color1) !important; color: white !important; - border: 0; + border: 2px; background-image: none !important; } .jp-extensionmanager-disclaimer-enable { - background-color: var(--jp-error-color1) !important; + background-color: var(--jp-brand-color1) !important; color: white !important; - border: 0; + border: 2px; background-image: none !important; } diff --git a/packages/filebrowser-extension/package.json b/packages/filebrowser-extension/package.json index 4f1d5ce..0d991f6 100644 --- a/packages/filebrowser-extension/package.json +++ b/packages/filebrowser-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/filebrowser-extension", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Filebrowser Widget Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -37,27 +37,26 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docmanager": "^3.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/filebrowser": "^3.3.2", - "@jupyterlab/launcher": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/settingregistry": "^3.3.2", - "@jupyterlab/statedb": "^3.3.2", - "@jupyterlab/statusbar": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/commands": "^1.12.0", - "@lumino/widgets": "^1.19.0" + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/filebrowser": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.12", + "@jupyterlab/statedb": "^4.0.0-alpha.12", + "@jupyterlab/statusbar": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/algorithm": "^1.9.1", + "@lumino/commands": "^1.20.0", + "@lumino/widgets": "^1.33.0" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/filebrowser-extension/schema/browser.json b/packages/filebrowser-extension/schema/browser.json index 6947106..799a445 100644 --- a/packages/filebrowser-extension/schema/browser.json +++ b/packages/filebrowser-extension/schema/browser.json @@ -6,10 +6,6 @@ { "id": "jp-mainmenu-file", "items": [ - { - "command": "filebrowser:create-main-launcher", - "rank": 1 - }, { "type": "separator", "rank": 1 @@ -27,6 +23,10 @@ { "id": "jp-mainmenu-view", "items": [ + { + "command": "filebrowser:toggle-main", + "rank": 1 + }, { "command": "filebrowser:toggle-hidden-files", "rank": 9.95 @@ -57,31 +57,11 @@ "selector": ".jp-DirListing-content", "rank": 0 }, - { - "command": "filebrowser:create-new-directory", - "selector": ".jp-DirListing-content", - "rank": 1 - }, { "command": "filebrowser:open", "selector": ".jp-DirListing-item[data-isdir]", "rank": 1 }, - { - "command": "filebrowser:create-new-file", - "selector": ".jp-DirListing-content", - "rank": 2 - }, - { - "command": "filebrowser:create-new-markdown-file", - "selector": ".jp-DirListing-content", - "rank": 3 - }, - { - "command": "filebrowser:paste", - "selector": ".jp-DirListing-content", - "rank": 4 - }, { "type": "separator", "selector": ".jp-DirListing-item[data-isdir]", @@ -107,6 +87,11 @@ "selector": ".jp-DirListing-item[data-isdir=\"false\"]", "rank": 8 }, + { + "command": "filebrowser:paste", + "selector": ".jp-DirListing-content", + "rank": 8.5 + }, { "command": "filebrowser:duplicate", "selector": ".jp-DirListing-item[data-isdir=\"false\"]", @@ -119,7 +104,7 @@ }, { "command": "filebrowser:shutdown", - "selector": ".jp-DirListing-item[data-isdir=\"false\"]", + "selector": ".jp-DirListing-item[data-isdir=\"false\"].jp-mod-running", "rank": 11 }, { @@ -137,21 +122,36 @@ "selector": ".jp-DirListing-header", "rank": 14 }, + { + "command": "filebrowser:toggle-file-checkboxes", + "selector": ".jp-DirListing-header", + "rank": 15 + }, { "command": "filebrowser:share-main", "selector": ".jp-DirListing-item[data-isdir]", - "rank": 15 + "rank": 16 + }, + { + "type": "separator", + "selector": ".jp-DirListing-item[data-isdir]", + "rank": 50 + }, + { + "command": "filebrowser:create-new-file", + "selector": ".jp-DirListing-content", + "rank": 51 + }, + { + "command": "filebrowser:create-new-directory", + "selector": ".jp-DirListing-content", + "rank": 55 } ] }, "title": "File Browser", "description": "File Browser settings.", "jupyter.lab.shortcuts": [ - { - "command": "filebrowser:create-main-launcher", - "keys": ["Accel Shift L"], - "selector": "body" - }, { "command": "filebrowser:toggle-main", "keys": ["Accel Shift F"], @@ -206,6 +206,12 @@ "description": "Whether to apply fuzzy algorithm while filtering on file names", "default": true }, + "filterDirectories": { + "type": "boolean", + "title": "Filter directories", + "description": "Whether to apply the search on directories", + "default": true + }, "showLastModifiedColumn": { "type": "boolean", "title": "Show last modified column", @@ -215,7 +221,13 @@ "showHiddenFiles": { "type": "boolean", "title": "Show hidden files", - "description": "Whether to show hidden files", + "description": "Whether to show hidden files. The server parameter `ContentsManager.allow_hidden` must be set to `True` to display hidden files.", + "default": false + }, + "showFileCheckboxes": { + "type": "boolean", + "title": "Use checkboxes to select items", + "description": "Whether to show checkboxes next to files and folders", "default": false } }, diff --git a/packages/filebrowser-extension/schema/open-browser-tab.json b/packages/filebrowser-extension/schema/open-browser-tab.json index 3a26863..bc03429 100644 --- a/packages/filebrowser-extension/schema/open-browser-tab.json +++ b/packages/filebrowser-extension/schema/open-browser-tab.json @@ -6,7 +6,7 @@ { "command": "filebrowser:open-browser-tab", "selector": ".jp-DirListing-item[data-isdir=\"false\"]", - "rank": 3 + "rank": 1.6 } ] }, diff --git a/packages/filebrowser-extension/schema/open-with.json b/packages/filebrowser-extension/schema/open-with.json index 58ab037..8038dd4 100644 --- a/packages/filebrowser-extension/schema/open-with.json +++ b/packages/filebrowser-extension/schema/open-with.json @@ -6,7 +6,7 @@ { "type": "submenu", "selector": ".jp-DirListing-item[data-isdir=\"false\"]", - "rank": 2, + "rank": 1.3, "submenu": { "id": "jp-contextmenu-open-with", "label": "Open With", diff --git a/packages/filebrowser-extension/schema/widget.json b/packages/filebrowser-extension/schema/widget.json new file mode 100644 index 0000000..776866a --- /dev/null +++ b/packages/filebrowser-extension/schema/widget.json @@ -0,0 +1,88 @@ +{ + "title": "File Browser Widget", + "description": "File Browser widget settings.", + "jupyter.lab.toolbars": { + "FileBrowser": [ + { + "name": "new-notebook", + "command": "notebook:create-new", + "icon": "ui-components:add", + "rank": 5 + }, + { + "name": "new-directory", + "command": "filebrowser:create-new-directory", + "rank": 10 + }, + { "name": "uploader", "rank": 20 }, + { + "name": "new-terminal", + "command": "terminal:create-new", + "rank": 30 + }, + { "name": "refresh", "command": "filebrowser:refresh", "rank": 50 } + ] + }, + "jupyter.lab.transform": true, + "properties": { + "toolbar": { + "title": "File browser toolbar items", + "description": "Note: To disable a toolbar item,\ncopy it to User Preferences and add the\n\"disabled\" key. The following example will disable the uploader button:\n{\n \"toolbar\": [\n {\n \"name\": \"uploader\",\n \"disabled\": true\n }\n ]\n}\n\nToolbar description:", + "items": { + "$ref": "#/definitions/toolbarItem" + }, + "type": "array", + "default": [] + } + }, + "additionalProperties": false, + "type": "object", + "definitions": { + "toolbarItem": { + "properties": { + "name": { + "title": "Unique name", + "type": "string" + }, + "args": { + "title": "Command arguments", + "type": "object" + }, + "command": { + "title": "Command id", + "type": "string", + "default": "" + }, + "disabled": { + "title": "Whether the item is ignored or not", + "type": "boolean", + "default": false + }, + "icon": { + "title": "Item icon id", + "description": "If defined, it will override the command icon", + "type": "string" + }, + "label": { + "title": "Item label", + "description": "If defined, it will override the command label", + "type": "string" + }, + "type": { + "title": "Item type", + "type": "string", + "enum": ["command", "spacer"] + }, + "rank": { + "title": "Item rank", + "type": "number", + "minimum": 0, + "default": 50 + } + }, + "required": ["name"], + "additionalProperties": false, + "type": "object" + } + } +} diff --git a/packages/filebrowser-extension/src/index.ts b/packages/filebrowser-extension/src/index.ts index f96c50d..8d943d0 100644 --- a/packages/filebrowser-extension/src/index.ts +++ b/packages/filebrowser-extension/src/index.ts @@ -11,15 +11,17 @@ import { IRouter, ITreePathUpdater, JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, + JupyterLab } from '@jupyterlab/application'; import { Clipboard, + createToolbarFactory, ICommandPalette, InputDialog, - MainAreaWidget, + IToolbarWidgetRegistry, + setToolbar, showErrorMessage, - ToolbarButton, WidgetTracker } from '@jupyterlab/apputils'; import { PageConfig, PathExt } from '@jupyterlab/coreutils'; @@ -29,9 +31,10 @@ import { FileBrowser, FileUploadStatus, FilterFileBrowserModel, - IFileBrowserFactory + IFileBrowserCommands, + IFileBrowserFactory, + Uploader } from '@jupyterlab/filebrowser'; -import { Launcher } from '@jupyterlab/launcher'; import { Contents } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { IStateDB } from '@jupyterlab/statedb'; @@ -46,10 +49,13 @@ import { editIcon, fileIcon, folderIcon, + IDisposableMenuItem, linkIcon, markdownIcon, newFolderIcon, pasteIcon, + RankedMenu, + refreshIcon, stopIcon, textEditorIcon } from '@jupyterlab/ui-components'; @@ -57,6 +63,9 @@ import { find, IIterator, map, reduce, toArray } from '@lumino/algorithm'; import { CommandRegistry } from '@lumino/commands'; import { ContextMenu } from '@lumino/widgets'; +const FILE_BROWSER_FACTORY = 'FileBrowser'; +const FILE_BROWSER_PLUGIN_ID = '@jupyterlab/filebrowser-extension:browser'; + /** * The command IDs used by the file browser plugin. */ @@ -65,9 +74,6 @@ namespace CommandIDs { export const copyDownloadLink = 'filebrowser:copy-download-link'; - // For main browser only. - export const createLauncher = 'filebrowser:create-main-launcher'; - export const cut = 'filebrowser:cut'; export const del = 'filebrowser:delete'; @@ -99,6 +105,8 @@ namespace CommandIDs { export const createNewMarkdownFile = 'filebrowser:create-new-markdown-file'; + export const refresh = 'filebrowser:refresh'; + export const rename = 'filebrowser:rename'; // For main browser only. @@ -122,6 +130,8 @@ namespace CommandIDs { export const search = 'filebrowser:search'; export const toggleHiddenFiles = 'filebrowser:toggle-hidden-files'; + + export const toggleFileCheckboxes = 'filebrowser:toggle-file-checkboxes'; } /** @@ -133,7 +143,7 @@ const namespace = 'filebrowser'; * The default file browser extension. */ const browser: JupyterFrontEndPlugin = { - id: '@jupyterlab/filebrowser-extension:browser', + id: FILE_BROWSER_PLUGIN_ID, requires: [IFileBrowserFactory, ITranslator], optional: [ ILayoutRestorer, @@ -141,6 +151,7 @@ const browser: JupyterFrontEndPlugin = { ITreePathUpdater, ICommandPalette ], + provides: IFileBrowserCommands, autoStart: true, activate: async ( app: JupyterFrontEnd, @@ -190,62 +201,47 @@ const browser: JupyterFrontEndPlugin = { updateBrowserTitle(); }); - void Promise.all([app.restored, browser.model.restored]).then(() => { + return void Promise.all([app.restored, browser.model.restored]).then(() => { if (treePathUpdater) { browser.model.pathChanged.connect((sender, args) => { treePathUpdater(args.newValue); }); } - let navigateToCurrentDirectory: boolean = false; - let showLastModifiedColumn: boolean = true; - let useFuzzyFilter: boolean = true; - let showHiddenFiles: boolean = false; - if (settingRegistry) { - void settingRegistry - .load('@jupyterlab/filebrowser-extension:browser') - .then(settings => { - settings.changed.connect(settings => { - navigateToCurrentDirectory = settings.get( - 'navigateToCurrentDirectory' - ).composite as boolean; - browser.navigateToCurrentDirectory = navigateToCurrentDirectory; - }); - navigateToCurrentDirectory = settings.get( - 'navigateToCurrentDirectory' - ).composite as boolean; - browser.navigateToCurrentDirectory = navigateToCurrentDirectory; - - settings.changed.connect(settings => { - showLastModifiedColumn = settings.get('showLastModifiedColumn') - .composite as boolean; - browser.showLastModifiedColumn = showLastModifiedColumn; - }); - showLastModifiedColumn = settings.get('showLastModifiedColumn') - .composite as boolean; - - browser.showLastModifiedColumn = showLastModifiedColumn; - - settings.changed.connect(settings => { - useFuzzyFilter = settings.get('useFuzzyFilter') - .composite as boolean; - browser.useFuzzyFilter = useFuzzyFilter; - }); - useFuzzyFilter = settings.get('useFuzzyFilter') - .composite as boolean; - browser.useFuzzyFilter = useFuzzyFilter; + void settingRegistry.load(FILE_BROWSER_PLUGIN_ID).then(settings => { + /** + * File browser configuration. + */ + const fileBrowserConfig = { + navigateToCurrentDirectory: false, + showLastModifiedColumn: true, + useFuzzyFilter: true, + showHiddenFiles: false, + showFileCheckboxes: false + }; + const fileBrowserModelConfig = { + filterDirectories: true + }; + + function onSettingsChanged( + settings: ISettingRegistry.ISettings + ): void { + let key: keyof typeof fileBrowserConfig; + for (key in fileBrowserConfig) { + const value = settings.get(key).composite as boolean; + fileBrowserConfig[key] = value; + browser[key] = value; + } - settings.changed.connect(settings => { - showHiddenFiles = settings.get('showHiddenFiles') - .composite as boolean; - browser.showHiddenFiles = showHiddenFiles; - }); - showHiddenFiles = settings.get('showHiddenFiles') + const value = settings.get('filterDirectories') .composite as boolean; - - browser.showHiddenFiles = showHiddenFiles; - }); + fileBrowserModelConfig.filterDirectories = value; + browser.model.filterDirectories = value; + } + settings.changed.connect(onSettingsChanged); + onSettingsChanged(settings); + }); } }); } @@ -258,14 +254,20 @@ const factory: JupyterFrontEndPlugin = { id: '@jupyterlab/filebrowser-extension:factory', provides: IFileBrowserFactory, requires: [IDocumentManager, ITranslator], - optional: [IStateDB, IRouter, JupyterFrontEnd.ITreeResolver], + optional: [ + IStateDB, + IRouter, + JupyterFrontEnd.ITreeResolver, + JupyterLab.IInfo + ], activate: async ( app: JupyterFrontEnd, docManager: IDocumentManager, translator: ITranslator, state: IStateDB | null, router: IRouter | null, - tree: JupyterFrontEnd.ITreeResolver | null + tree: JupyterFrontEnd.ITreeResolver | null, + info: JupyterLab.IInfo | null ): Promise => { const { commands } = app; const tracker = new WidgetTracker({ namespace }); @@ -279,6 +281,12 @@ const factory: JupyterFrontEndPlugin = { manager: docManager, driveName: options.driveName || '', refreshInterval: options.refreshInterval, + refreshStandby: () => { + if (info) { + return !info.isConnected || 'when-hidden'; + } + return 'when-hidden'; + }, state: options.state === null ? undefined @@ -311,20 +319,18 @@ const factory: JupyterFrontEndPlugin = { * Users will still be able to retrieve files from the file download URLs the * server provides. */ -// @ts-ignore -let downloadPlugin: JupyterFrontEndPlugin; -downloadPlugin = { +const downloadPlugin: JupyterFrontEndPlugin = { id: '@jupyterlab/filebrowser-extension:download', requires: [IFileBrowserFactory, ITranslator], autoStart: true, activate: ( - app: JupyterFrontEnd, - factory: IFileBrowserFactory, - translator: ITranslator + app: JupyterFrontEnd, + factory: IFileBrowserFactory, + translator: ITranslator ): void => { const trans = translator.load('jupyterlab'); - const {commands} = app; - const {tracker} = factory; + const { commands } = app; + const { tracker } = factory; commands.addCommand(CommandIDs.download, { execute: () => { @@ -334,7 +340,7 @@ downloadPlugin = { return widget.download(); } }, - icon: downloadIcon.bindprops({stylesheet: 'menuItem'}), + icon: downloadIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Download') }); @@ -346,12 +352,12 @@ downloadPlugin = { } return widget.model.manager.services.contents - .getDownloadUrl(widget.selectedItems().next()!.path) - .then(url => { - Clipboard.copyToSystem(url); - }); + .getDownloadUrl(widget.selectedItems().next()!.path) + .then(url => { + Clipboard.copyToSystem(url); + }); }, - icon: copyIcon.bindprops({stylesheet: 'menuItem'}), + icon: copyIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Copy Download Link'), mnemonic: 0 }); @@ -363,12 +369,22 @@ downloadPlugin = { */ const browserWidget: JupyterFrontEndPlugin = { id: '@jupyterlab/filebrowser-extension:widget', - requires: [IDocumentManager, IFileBrowserFactory, ITranslator, ILabShell], + requires: [ + IDocumentManager, + IFileBrowserFactory, + ISettingRegistry, + IToolbarWidgetRegistry, + ITranslator, + ILabShell, + IFileBrowserCommands + ], autoStart: true, activate: ( app: JupyterFrontEnd, docManager: IDocumentManager, factory: IFileBrowserFactory, + settings: ISettingRegistry, + toolbarRegistry: IToolbarWidgetRegistry, translator: ITranslator, labShell: ILabShell ): void => { @@ -381,9 +397,29 @@ const browserWidget: JupyterFrontEndPlugin = { browser.node.setAttribute('aria-label', trans.__('File Browser Section')); browser.title.icon = folderIcon; - labShell.add(browser, 'left', { rank: 100 }); + // Toolbar + toolbarRegistry.addFactory( + FILE_BROWSER_FACTORY, + 'uploader', + (browser: FileBrowser) => + new Uploader({ model: browser.model, translator }) + ); + + setToolbar( + browser, + createToolbarFactory( + toolbarRegistry, + settings, + FILE_BROWSER_FACTORY, + browserWidget.id, + translator + ) + ); + + labShell.add(browser, 'left', { rank: 100, type: 'File Browser' }); commands.addCommand(CommandIDs.showBrowser, { + label: trans.__('Open the file browser for the provided `path`.'), execute: args => { const path = (args.path as string) || ''; const browserForPath = Private.getBrowserForPath(path, factory); @@ -414,6 +450,7 @@ const browserWidget: JupyterFrontEndPlugin = { }); commands.addCommand(CommandIDs.hideBrowser, { + label: trans.__('Hide the file browser.'), execute: () => { const widget = tracker.currentWidget; if (widget && !widget.isHidden) { @@ -431,21 +468,6 @@ const browserWidget: JupyterFrontEndPlugin = { }); void Promise.all([app.restored, browser.model.restored]).then(() => { - function maybeCreate() { - // Create a launcher if there are no open items. - if ( - labShell.isEmpty('main') && - commands.hasCommand('launcher:create') - ) { - void Private.createLauncher(commands, browser); - } - } - - // When layout is modified, create a launcher if there are no open items. - labShell.layoutModified.connect(() => { - maybeCreate(); - }); - // Whether to automatically navigate to a document's current directory labShell.currentChanged.connect(async (_, change) => { if (browser.navigateToCurrentDirectory && change.newValue) { @@ -464,8 +486,6 @@ const browserWidget: JupyterFrontEndPlugin = { } } }); - - maybeCreate(); }); } }; @@ -481,20 +501,18 @@ const browserWidget: JupyterFrontEndPlugin = { * /user-redirect URL for JupyterHub), disable this plugin and replace it * with another implementation. */ -// @ts-ignore -let shareFile: JupyterFrontEndPlugin; -shareFile = { +const shareFile: JupyterFrontEndPlugin = { id: '@jupyterlab/filebrowser-extension:share-file', requires: [IFileBrowserFactory, ITranslator], autoStart: true, activate: ( - app: JupyterFrontEnd, - factory: IFileBrowserFactory, - translator: ITranslator + app: JupyterFrontEnd, + factory: IFileBrowserFactory, + translator: ITranslator ): void => { const trans = translator.load('jupyterlab'); - const {commands} = app; - const {tracker} = factory; + const { commands } = app; + const { tracker } = factory; commands.addCommand(CommandIDs.copyShareableLink, { execute: () => { @@ -505,17 +523,17 @@ shareFile = { } Clipboard.copyToSystem( - PageConfig.getUrl({ - workspace: PageConfig.defaultWorkspace, - treePath: model.path, - toShare: true - }) + PageConfig.getUrl({ + workspace: PageConfig.defaultWorkspace, + treePath: model.path, + toShare: true + }) ); }, isVisible: () => - !!tracker.currentWidget && - toArray(tracker.currentWidget.selectedItems()).length === 1, - icon: linkIcon.bindprops({stylesheet: 'menuItem'}), + !!tracker.currentWidget && + toArray(tracker.currentWidget.selectedItems()).length === 1, + icon: linkIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Copy Shareable Link') }); } @@ -535,38 +553,43 @@ const openWithPlugin: JupyterFrontEndPlugin = { const { docRegistry } = app; const { tracker } = factory; + let items: IDisposableMenuItem[] = []; + function updateOpenWithMenu(contextMenu: ContextMenu) { const openWith = - contextMenu.menu.items.find( + (contextMenu.menu.items.find( item => item.type === 'submenu' && item.submenu?.id === 'jp-contextmenu-open-with' - )?.submenu ?? null; + )?.submenu as RankedMenu) ?? null; if (!openWith) { return; // Bail early if the open with menu is not displayed } // clear the current menu items + items.forEach(item => item.dispose()); + items.length = 0; + // Ensure that the menu is empty openWith.clearItems(); // get the widget factories that could be used to open all of the items // in the current filebrowser selection const factories = tracker.currentWidget - ? Private.OpenWith.intersection( + ? Private.OpenWith.intersection( map(tracker.currentWidget.selectedItems(), i => { return Private.OpenWith.getFactories(docRegistry, i); }) ) - : new Set(); + : new Set(); // make new menu items from the widget factories - factories.forEach(factory => { + items = [...factories].map(factory => openWith.addItem({ - args: { factory: factory }, + args: { factory: factory.name, label: factory.label || factory.name }, command: CommandIDs.open - }); - }); + }) + ); } app.contextMenu.opened.connect(updateOpenWithMenu); @@ -596,25 +619,44 @@ const openBrowserTabPlugin: JupyterFrontEndPlugin = { const { tracker } = factory; commands.addCommand(CommandIDs.openBrowserTab, { - execute: () => { + execute: args => { const widget = tracker.currentWidget; if (!widget) { return; } + const mode = args['mode'] as string | undefined; + return Promise.all( toArray( map(widget.selectedItems(), item => { - return commands.execute('docmanager:open-browser-tab', { - path: item.path - }); + if (mode === 'single-document') { + const url = PageConfig.getUrl({ + mode: 'single-document', + treePath: item.path + }); + const opened = window.open(); + if (opened) { + opened.opener = null; + opened.location.href = url; + } else { + throw new Error('Failed to open new browser tab.'); + } + } else { + return commands.execute('docmanager:open-browser-tab', { + path: item.path + }); + } }) ) ); }, icon: addIcon.bindprops({ stylesheet: 'menuItem' }), - label: trans.__('Open in New Browser Tab'), + label: args => + args['mode'] === 'single-document' + ? trans.__('Open in Simple Mode') + : trans.__('Open in New Browser Tab'), mnemonic: 0 }); } @@ -657,37 +699,6 @@ export const fileUploadStatus: JupyterFrontEndPlugin = { } }; -/** - * A plugin to add a launcher button to the file browser toolbar - */ -export const launcherToolbarButton: JupyterFrontEndPlugin = { - id: '@jupyterlab/filebrowser-extension:launcher-toolbar-button', - autoStart: true, - requires: [IFileBrowserFactory, ITranslator], - activate: ( - app: JupyterFrontEnd, - factory: IFileBrowserFactory, - translator: ITranslator - ) => { - const { commands } = app; - const trans = translator.load('jupyterlab'); - const { defaultBrowser: browser } = factory; - - // Add a launcher toolbar item. - const launcher = new ToolbarButton({ - icon: addIcon, - onClick: () => { - if (commands.hasCommand('launcher:create')) { - return Private.createLauncher(commands, browser); - } - }, - tooltip: trans.__('New Launcher'), - actualOnClick: true - }); - browser.toolbar.insertItem(0, 'launch', launcher); - } -}; - /** * A plugin to open files from remote URLs */ @@ -835,6 +846,7 @@ function addCommands( }); commands.addCommand(CommandIDs.goToPath, { + label: trans.__('Update the file browser to display the provided `path`.'), execute: async args => { const path = (args.path as string) || ''; const showBrowser = !(args?.dontShowBrowser ?? false); @@ -984,7 +996,6 @@ function addCommands( return folderIcon.bindprops({ stylesheet: 'menuItem' }); } }, - // FIXME-TRANS: Is this localizable? label: args => (args['label'] || args['factory'] || trans.__('Open')) as string, mnemonic: 0 @@ -1024,7 +1035,7 @@ function addCommands( } }, icon: textEditorIcon.bindprops({ stylesheet: 'menuItem' }), - label: trans.__('New Text File') + label: trans.__('New File') }); commands.addCommand(CommandIDs.createNewMarkdownFile, { @@ -1039,6 +1050,19 @@ function addCommands( label: trans.__('New Markdown File') }); + commands.addCommand(CommandIDs.refresh, { + execute: args => { + const widget = tracker.currentWidget; + + if (widget) { + return widget.model.refresh(); + } + }, + icon: refreshIcon.bindprops({ stylesheet: 'menuItem' }), + caption: trans.__('Refresh the file browser.'), + label: trans.__('Refresh File List') + }); + commands.addCommand(CommandIDs.rename, { execute: args => { const widget = tracker.currentWidget; @@ -1085,6 +1109,7 @@ function addCommands( }); commands.addCommand(CommandIDs.toggleBrowser, { + label: trans.__('File Browser'), execute: () => { if (browser.isHidden) { return commands.execute(CommandIDs.showBrowser, void 0); @@ -1094,11 +1119,6 @@ function addCommands( } }); - commands.addCommand(CommandIDs.createLauncher, { - label: trans.__('New Launcher'), - execute: () => Private.createLauncher(commands, browser) - }); - if (settingRegistry) { commands.addCommand(CommandIDs.toggleNavigateToCurrentDirectory, { label: trans.__('Show Active File in File Browser'), @@ -1107,7 +1127,7 @@ function addCommands( const value = !browser.navigateToCurrentDirectory; const key = 'navigateToCurrentDirectory'; return settingRegistry - .set('@jupyterlab/filebrowser-extension:browser', key, value) + .set(FILE_BROWSER_PLUGIN_ID, key, value) .catch((reason: Error) => { console.error(`Failed to set navigateToCurrentDirectory setting`); }); @@ -1123,7 +1143,7 @@ function addCommands( const key = 'showLastModifiedColumn'; if (settingRegistry) { return settingRegistry - .set('@jupyterlab/filebrowser-extension:browser', key, value) + .set(FILE_BROWSER_PLUGIN_ID, key, value) .catch((reason: Error) => { console.error(`Failed to set showLastModifiedColumn setting`); }); @@ -1140,7 +1160,7 @@ function addCommands( const key = 'showHiddenFiles'; if (settingRegistry) { return settingRegistry - .set('@jupyterlab/filebrowser-extension:browser', key, value) + .set(FILE_BROWSER_PLUGIN_ID, key, value) .catch((reason: Error) => { console.error(`Failed to set showHiddenFiles setting`); }); @@ -1148,6 +1168,22 @@ function addCommands( } }); + commands.addCommand(CommandIDs.toggleFileCheckboxes, { + label: trans.__('Show File Checkboxes'), + isToggled: () => browser.showFileCheckboxes, + execute: () => { + const value = !browser.showFileCheckboxes; + const key = 'showFileCheckboxes'; + if (settingRegistry) { + return settingRegistry + .set(FILE_BROWSER_PLUGIN_ID, key, value) + .catch((reason: Error) => { + console.error(`Failed to set showFileCheckboxes setting`); + }); + } + } + }); + commands.addCommand(CommandIDs.search, { label: trans.__('Search on File Names'), execute: () => alert('search') @@ -1161,31 +1197,26 @@ function addCommands( } } +/** + * Export the plugins as default. + */ +const plugins: JupyterFrontEndPlugin[] = [ + factory, + browser, + shareFile, + fileUploadStatus, + downloadPlugin, + browserWidget, + openWithPlugin, + openBrowserTabPlugin, + openUrlPlugin +]; +export default plugins; + /** * A namespace for private module data. */ namespace Private { - /** - * Create a launcher for a given filebrowser widget. - */ - export function createLauncher( - commands: CommandRegistry, - browser: FileBrowser - ): Promise> { - const { model } = browser; - - return commands - .execute('launcher:create', { cwd: model.path }) - .then((launcher: MainAreaWidget) => { - model.pathChanged.connect(() => { - if (launcher.content) { - launcher.content.cwd = model.path; - } - }, launcher); - return launcher; - }); - } - /** * Get browser object given file path. */ @@ -1291,26 +1322,7 @@ namespace Private { }; router.routed.connect(listener); } -} - -/** - * Export the plugins as default. - */ -const plugins: JupyterFrontEndPlugin[] = [ - factory, - browser, - // shareFile, - fileUploadStatus, - // downloadPlugin, - browserWidget, - launcherToolbarButton, - openWithPlugin, - openBrowserTabPlugin, - openUrlPlugin -]; -export default plugins; -namespace Private { export namespace OpenWith { /** * Get the factories for the selected item @@ -1322,11 +1334,9 @@ namespace Private { export function getFactories( docRegistry: DocumentRegistry, item: Contents.IModel - ): Array { - const factories = docRegistry - .preferredWidgetFactories(item.path) - .map(f => f.name); - const notebookFactory = docRegistry.getWidgetFactory('notebook')?.name; + ): Array { + const factories = docRegistry.preferredWidgetFactories(item.path); + const notebookFactory = docRegistry.getWidgetFactory('notebook'); if ( notebookFactory && item.type === 'notebook' && diff --git a/packages/filebrowser-extension/style/index.css b/packages/filebrowser-extension/style/index.css index 8f48c1c..2e6863c 100644 --- a/packages/filebrowser-extension/style/index.css +++ b/packages/filebrowser-extension/style/index.css @@ -6,12 +6,11 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('https://github.com/~@lumino/widgets/style/index.css'); @import url('https://github.com/~@jupyterlab/ui-components/style/index.css'); -@import url('https://github.com/~@jupyterlab/apputils/style/index.css'); @import url('https://github.com/~@jupyterlab/statusbar/style/index.css'); +@import url('https://github.com/~@jupyterlab/apputils/style/index.css'); @import url('https://github.com/~@jupyterlab/docregistry/style/index.css'); @import url('https://github.com/~@jupyterlab/application/style/index.css'); @import url('https://github.com/~@jupyterlab/docmanager/style/index.css'); @import url('https://github.com/~@jupyterlab/filebrowser/style/index.css'); -@import url('https://github.com/~@jupyterlab/launcher/style/index.css'); @import url('https://github.com/base.css'); diff --git a/packages/filebrowser-extension/style/index.js b/packages/filebrowser-extension/style/index.js index 7b36e45..ecd1c4b 100644 --- a/packages/filebrowser-extension/style/index.js +++ b/packages/filebrowser-extension/style/index.js @@ -6,12 +6,11 @@ /* 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/apputils/style/index.js'; import '@jupyterlab/docregistry/style/index.js'; import '@jupyterlab/application/style/index.js'; import '@jupyterlab/docmanager/style/index.js'; import '@jupyterlab/filebrowser/style/index.js'; -import '@jupyterlab/launcher/style/index.js'; import './base.css'; diff --git a/packages/filebrowser-extension/tsconfig.json b/packages/filebrowser-extension/tsconfig.json index b4132ab..165d79d 100644 --- a/packages/filebrowser-extension/tsconfig.json +++ b/packages/filebrowser-extension/tsconfig.json @@ -24,9 +24,6 @@ { "path": "../filebrowser" }, - { - "path": "../launcher" - }, { "path": "../services" }, diff --git a/packages/filebrowser/.vscode/launch.json b/packages/filebrowser/.vscode/launch.json new file mode 100644 index 0000000..66fb4b8 --- /dev/null +++ b/packages/filebrowser/.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/filebrowser/babel.config.js b/packages/filebrowser/babel.config.js index 8b5c764..bf69a46 100644 --- a/packages/filebrowser/babel.config.js +++ b/packages/filebrowser/babel.config.js @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + module.exports = require('@jupyterlab/testutils/lib/babel.config'); diff --git a/packages/filebrowser/jest.config.js b/packages/filebrowser/jest.config.js index 178440a..64773dc 100644 --- a/packages/filebrowser/jest.config.js +++ b/packages/filebrowser/jest.config.js @@ -1,2 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const func = require('@jupyterlab/testutils/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/filebrowser/package.json b/packages/filebrowser/package.json index a6d452c..d7749eb 100644 --- a/packages/filebrowser/package.json +++ b/packages/filebrowser/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/filebrowser", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - FileBrowser Widget", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -41,35 +41,35 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docmanager": "^3.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/statedb": "^3.3.2", - "@jupyterlab/statusbar": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/coreutils": "^1.5.3", - "@lumino/disposable": "^1.4.3", - "@lumino/domutils": "^1.2.3", - "@lumino/dragdrop": "^1.7.1", - "@lumino/messaging": "^1.4.3", - "@lumino/polling": "^1.3.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docmanager": "^4.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/statedb": "^4.0.0-alpha.12", + "@jupyterlab/statusbar": "^4.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/algorithm": "^1.9.1", + "@lumino/coreutils": "^1.12.0", + "@lumino/disposable": "^1.10.1", + "@lumino/domutils": "^1.8.1", + "@lumino/dragdrop": "^1.14.0", + "@lumino/messaging": "^1.10.1", + "@lumino/polling": "^1.10.0", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "react": "^17.0.1" }, "devDependencies": { - "@jupyterlab/testutils": "^3.3.2", + "@jupyterlab/testutils": "^4.0.0-alpha.12", "@types/jest": "^26.0.10", "jest": "^26.4.2", "rimraf": "~3.0.0", "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/filebrowser/src/browser.ts b/packages/filebrowser/src/browser.ts index 09f968a..3cbb4a5 100644 --- a/packages/filebrowser/src/browser.ts +++ b/packages/filebrowser/src/browser.ts @@ -1,33 +1,32 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { - FilenameSearcher, - ReactWidget, - showErrorMessage, - Toolbar, - ToolbarButton -} from '@jupyterlab/apputils'; +import { showErrorMessage } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { Contents, ServerConnection } from '@jupyterlab/services'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; import { - ITranslator, - nullTranslator, - TranslationBundle -} from '@jupyterlab/translation'; -import { newFolderIcon, refreshIcon } from '@jupyterlab/ui-components'; + FilenameSearcher, + IScore, + ReactWidget, + SidePanel +} from '@jupyterlab/ui-components'; import { IIterator } from '@lumino/algorithm'; -import { PanelLayout, Widget } from '@lumino/widgets'; +import { Panel } from '@lumino/widgets'; import { BreadCrumbs } from './crumbs'; import { DirListing } from './listing'; import { FilterFileBrowserModel } from './model'; -import { Uploader } from './upload'; /** * The class name added to file browsers. */ const FILE_BROWSER_CLASS = 'jp-FileBrowser'; +/** + * The class name added to file browser panel (gather filter, breadcrumbs and listing). + */ +const FILE_BROWSER_PANEL_CLASS = 'jp-FileBrowser-Panel'; + /** * The class name added to the filebrowser crumbs node. */ @@ -55,64 +54,54 @@ const LISTING_CLASS = 'jp-FileBrowser-listing'; * and presents itself as a flat list of files and directories with * breadcrumbs. */ -export class FileBrowser extends Widget { +export class FileBrowser extends SidePanel { /** * Construct a new file browser. * * @param options - The file browser options. */ constructor(options: FileBrowser.IOptions) { - super(); + super({ content: new Panel(), translator: options.translator }); this.addClass(FILE_BROWSER_CLASS); + this.toolbar.addClass(TOOLBAR_CLASS); this.id = options.id; + const translator = (this.translator = options.translator ?? nullTranslator); const model = (this.model = options.model); const renderer = options.renderer; - const translator = this.translator; model.connectionFailure.connect(this._onConnectionFailure, this); - this.translator = options.translator || nullTranslator; this._manager = model.manager; - this._trans = this.translator.load('jupyterlab'); - this.crumbs = new BreadCrumbs({ model, translator }); - this.toolbar = new Toolbar(); + // a11y this.toolbar.node.setAttribute('role', 'navigation'); this.toolbar.node.setAttribute( 'aria-label', this._trans.__('file browser') ); - this._directoryPending = false; - const newFolder = new ToolbarButton({ - icon: newFolderIcon, - onClick: () => { - this.createNewDirectory(); - }, - tooltip: this._trans.__('New Folder') - }); - const uploader = new Uploader({ model, translator: this.translator }); + this._directoryPending = false; - const refresher = new ToolbarButton({ - icon: refreshIcon, - onClick: () => { - void model.refresh(); - }, - tooltip: this._trans.__('Refresh File List') - }); + // File browser widgets container + this.mainPanel = new Panel(); + this.mainPanel.addClass(FILE_BROWSER_PANEL_CLASS); + this.mainPanel.title.label = this._trans.__('File Browser'); - this.toolbar.addItem('newFolder', newFolder); - this.toolbar.addItem('upload', uploader); - this.toolbar.addItem('refresher', refresher); + this.crumbs = new BreadCrumbs({ model, translator }); + this.crumbs.addClass(CRUMBS_CLASS); this.listing = this.createDirListing({ model, renderer, - translator: this.translator + translator }); + this.listing.addClass(LISTING_CLASS); this._filenameSearcher = FilenameSearcher({ - updateFilter: (filterFn: (item: string) => boolean) => { + updateFilter: ( + filterFn: (item: string) => Partial | null, + query?: string + ) => { this.listing.model.setFilter(value => { return filterFn(value.name.toLowerCase()); }); @@ -120,17 +109,13 @@ export class FileBrowser extends Widget { useFuzzyFilter: this._useFuzzyFilter, placeholder: this._trans.__('Filter files by name') }); - - this.crumbs.addClass(CRUMBS_CLASS); - this.toolbar.addClass(TOOLBAR_CLASS); this._filenameSearcher.addClass(FILTERBOX_CLASS); - this.listing.addClass(LISTING_CLASS); - this.layout = new PanelLayout(); - this.layout.addWidget(this.toolbar); - this.layout.addWidget(this._filenameSearcher); - this.layout.addWidget(this.crumbs); - this.layout.addWidget(this.listing); + this.mainPanel.addWidget(this._filenameSearcher); + this.mainPanel.addWidget(this.crumbs); + this.mainPanel.addWidget(this.listing); + + this.addWidget(this.mainPanel); if (options.restore !== false) { void model.restore(this.id); @@ -142,16 +127,6 @@ export class FileBrowser extends Widget { */ readonly model: FilterFileBrowserModel; - /** - * The toolbar used by the file browser. - */ - readonly toolbar: Toolbar; - - /** - * Override Widget.layout with a more specific PanelLayout type. - */ - layout: PanelLayout; - /** * Whether to show active file in file browser */ @@ -185,8 +160,15 @@ export class FileBrowser extends Widget { set useFuzzyFilter(value: boolean) { this._useFuzzyFilter = value; + // Detach and dispose the current widget + this._filenameSearcher.parent = null; + this._filenameSearcher.dispose(); + this._filenameSearcher = FilenameSearcher({ - updateFilter: (filterFn: (item: string) => boolean) => { + updateFilter: ( + filterFn: (item: string) => Partial | null, + query?: string + ) => { this.listing.model.setFilter(value => { return filterFn(value.name.toLowerCase()); }); @@ -197,13 +179,7 @@ export class FileBrowser extends Widget { }); this._filenameSearcher.addClass(FILTERBOX_CLASS); - this.layout.removeWidget(this._filenameSearcher); - this.layout.removeWidget(this.crumbs); - this.layout.removeWidget(this.listing); - - this.layout.addWidget(this._filenameSearcher); - this.layout.addWidget(this.crumbs); - this.layout.addWidget(this.listing); + this.mainPanel.insertWidget(0, this._filenameSearcher); } /** @@ -218,6 +194,22 @@ export class FileBrowser extends Widget { this._showHiddenFiles = value; } + /** + * Whether to show checkboxes next to files and folders + */ + get showFileCheckboxes(): boolean { + return this._showFileCheckboxes; + } + + set showFileCheckboxes(value: boolean) { + if (this.listing.setColumnVisibility) { + this.listing.setColumnVisibility('is_selected', value); + this._showFileCheckboxes = value; + } else { + console.warn('Listing does not support toggling column visibility'); + } + } + /** * Create an iterator over the listing's selected items. * @@ -425,7 +417,8 @@ export class FileBrowser extends Widget { protected listing: DirListing; protected crumbs: BreadCrumbs; - private _trans: TranslationBundle; + protected mainPanel: Panel; + private _filenameSearcher: ReactWidget; private _manager: IDocumentManager; private _directoryPending: boolean; @@ -434,6 +427,7 @@ export class FileBrowser extends Widget { private _showLastModifiedColumn: boolean = true; private _useFuzzyFilter: boolean = true; private _showHiddenFiles: boolean = false; + private _showFileCheckboxes: boolean = false; } /** diff --git a/packages/filebrowser/src/crumbs.ts b/packages/filebrowser/src/crumbs.ts index bb12f13..2b7c006 100644 --- a/packages/filebrowser/src/crumbs.ts +++ b/packages/filebrowser/src/crumbs.ts @@ -9,7 +9,11 @@ import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; -import { ellipsesIcon, folderIcon } from '@jupyterlab/ui-components'; +import { + ellipsesIcon, + homeIcon as preferredIcon, + folderIcon as rootIcon +} from '@jupyterlab/ui-components'; import { ArrayExt } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; import { IDragEvent } from '@lumino/dragdrop'; @@ -25,7 +29,12 @@ const BREADCRUMB_CLASS = 'jp-BreadCrumbs'; /** * The class name for the breadcrumbs home node */ -const BREADCRUMB_HOME_CLASS = 'jp-BreadCrumbs-home'; +const BREADCRUMB_ROOT_CLASS = 'jp-BreadCrumbs-home'; + +/** + * The class name for the breadcrumbs preferred node + */ +const BREADCRUMB_PREFERRED_CLASS = 'jp-BreadCrumbs-preferred'; /** * The class name added to the breadcrumb node. @@ -64,6 +73,11 @@ export class BreadCrumbs extends Widget { this.addClass(BREADCRUMB_CLASS); this._crumbs = Private.createCrumbs(); this._crumbSeps = Private.createCrumbSeparators(); + const hasPreferred = PageConfig.getOption('preferredPath'); + this._hasPreferred = hasPreferred && hasPreferred !== '/' ? true : false; + if (this._hasPreferred) { + this.node.appendChild(this._crumbs[Private.Crumb.Preferred]); + } this.node.appendChild(this._crumbs[Private.Crumb.Home]); this._model.refreshed.connect(this.update, this); } @@ -134,7 +148,12 @@ export class BreadCrumbs extends Widget { // Update the breadcrumb list. const contents = this._model.manager.services.contents; const localPath = contents.localPath(this._model.path); - Private.updateCrumbs(this._crumbs, this._crumbSeps, localPath); + Private.updateCrumbs( + this._crumbs, + this._crumbSeps, + localPath, + this._hasPreferred + ); } /** @@ -149,9 +168,21 @@ export class BreadCrumbs extends Widget { // Find a valid click target. let node = event.target as HTMLElement; while (node && node !== this.node) { + if (node.classList.contains(BREADCRUMB_PREFERRED_CLASS)) { + this._model + .cd(PageConfig.getOption('preferredPath')) + .catch(error => + showErrorMessage(this._trans.__('Open Error'), error) + ); + + // Stop the event propagation. + event.preventDefault(); + event.stopPropagation(); + return; + } if ( node.classList.contains(BREADCRUMB_ITEM_CLASS) || - node.classList.contains(BREADCRUMB_HOME_CLASS) + node.classList.contains(BREADCRUMB_ROOT_CLASS) ) { const index = ArrayExt.findFirstIndex( this._crumbs, @@ -275,6 +306,7 @@ export class BreadCrumbs extends Widget { protected translator: ITranslator; private _trans: TranslationBundle; private _model: FileBrowserModel; + private _hasPreferred: boolean; private _crumbs: ReadonlyArray; private _crumbSeps: ReadonlyArray; } @@ -310,7 +342,8 @@ namespace Private { Home, Ellipsis, Parent, - Current + Current, + Preferred } /** @@ -319,16 +352,23 @@ namespace Private { export function updateCrumbs( breadcrumbs: ReadonlyArray, separators: ReadonlyArray, - path: string - ) { + path: string, + hasPreferred: boolean + ): void { const node = breadcrumbs[0].parentNode as HTMLElement; - // Remove all but the home node. + // Remove all but the home or preferred node. const firstChild = node.firstChild as HTMLElement; while (firstChild && firstChild.nextSibling) { node.removeChild(firstChild.nextSibling); } - node.appendChild(separators[0]); + + if (hasPreferred) { + node.appendChild(breadcrumbs[Crumb.Home]); + node.appendChild(separators[0]); + } else { + node.appendChild(separators[0]); + } const parts = path.split('/'); if (parts.length > 2) { @@ -357,8 +397,8 @@ namespace Private { * Create the breadcrumb nodes. */ export function createCrumbs(): ReadonlyArray { - const home = folderIcon.element({ - className: BREADCRUMB_HOME_CLASS, + const home = rootIcon.element({ + className: BREADCRUMB_ROOT_CLASS, tag: 'span', title: PageConfig.getOption('serverRoot') || 'Jupyter Server Root', stylesheet: 'breadCrumb' @@ -372,7 +412,13 @@ namespace Private { parent.className = BREADCRUMB_ITEM_CLASS; const current = document.createElement('span'); current.className = BREADCRUMB_ITEM_CLASS; - return [home, ellipsis, parent, current]; + const preferred = preferredIcon.element({ + className: BREADCRUMB_PREFERRED_CLASS, + tag: 'span', + title: PageConfig.getOption('preferredPath') || 'Jupyter Preferred Path', + stylesheet: 'breadCrumb' + }); + return [home, ellipsis, parent, current, preferred]; } /** diff --git a/packages/filebrowser/src/listing.ts b/packages/filebrowser/src/listing.ts index 7820273..3916350 100644 --- a/packages/filebrowser/src/listing.ts +++ b/packages/filebrowser/src/listing.ts @@ -95,6 +95,12 @@ const ITEM_ICON_CLASS = 'jp-DirListing-itemIcon'; */ const ITEM_MODIFIED_CLASS = 'jp-DirListing-itemModified'; +/** + * The class name added to the label element that wraps each item's checkbox and + * the header's check-all checkbox. + */ +const CHECKBOX_WRAPPER_CLASS = 'jp-DirListing-checkboxWrapper'; + /** * The class name added to the dir listing editor node. */ @@ -355,7 +361,8 @@ export class DirListing extends Widget { each(this._clipboard, path => { if (this._isCut) { - const parts = path.split('/'); + const localPath = this._manager.services.contents.localPath(path); + const parts = localPath.split('/'); const name = parts[parts.length - 1]; const newPath = PathExt.join(basePath, name); promises.push(this._model.manager.rename(path, newPath)); @@ -785,12 +792,33 @@ export class DirListing extends Widget { } // Remove extra classes from the nodes. - nodes.forEach(item => { - item.classList.remove(SELECTED_CLASS); - item.classList.remove(RUNNING_CLASS); - item.classList.remove(CUT_CLASS); + nodes.forEach(node => { + node.classList.remove(SELECTED_CLASS); + node.classList.remove(RUNNING_CLASS); + node.classList.remove(CUT_CLASS); + const checkbox = renderer.getCheckboxNode(node); + if (checkbox) { + // Uncheck each file checkbox + checkbox.checked = false; + } }); + // Put the check-all checkbox in the header into the correct state + const checkAllCheckbox = renderer.getCheckboxNode(this.headerNode); + if (checkAllCheckbox) { + const totalSelected = Object.keys(this.selection).length; + const allSelected = items.length > 0 && totalSelected === items.length; + const someSelected = !allSelected && totalSelected > 0; + checkAllCheckbox.checked = allSelected; + checkAllCheckbox.indeterminate = someSelected; + // Stash the state in data attributes so we can access them in the click + // handler (because in the click handler, checkbox.checked and + // checkbox.indeterminate do not hold the previous value; they hold the + // next value). + checkAllCheckbox.dataset.checked = String(allSelected); + checkAllCheckbox.dataset.indeterminate = String(someSelected); + } + // Add extra classes to item nodes based on widget state. items.forEach((item, i) => { const node = nodes[i]; @@ -808,6 +836,11 @@ export class DirListing extends Widget { if (this._isCut && this._model.path === this._prevPath) { node.classList.add(CUT_CLASS); } + + const checkbox = renderer.getCheckboxNode(node); + if (checkbox) { + checkbox.checked = true; + } } // add metadata to the node @@ -839,7 +872,7 @@ export class DirListing extends Widget { node.classList.add(RUNNING_CLASS); if (specs && name) { const spec = specs.kernelspecs[name]; - name = spec ? spec.display_name : 'unknown'; // FIXME-TRANS: Is this localizable? + name = spec ? spec.display_name : this._trans.__('unknown'); } node.title = this._trans.__('%1\nKernel: %2', node.title, name); } @@ -872,6 +905,20 @@ export class DirListing extends Widget { ); } + /** + * Would this click (or other event type) hit the checkbox by default? + */ + protected isWithinCheckboxHitArea(event: Event): boolean { + let element: HTMLElement | null = event.target as HTMLElement; + while (element) { + if (element.classList.contains(CHECKBOX_WRAPPER_CLASS)) { + return true; + } + element = element.parentElement; + } + return false; + } + /** * Handle the `'click'` event for the widget. */ @@ -879,10 +926,32 @@ export class DirListing extends Widget { const target = event.target as HTMLElement; const header = this.headerNode; + const renderer = this._renderer; if (header.contains(target)) { - const state = this.renderer.handleHeaderClick(header, event); - if (state) { - this.sort(state); + const checkbox = renderer.getCheckboxNode(header); + if (checkbox && this.isWithinCheckboxHitArea(event)) { + const previouslyUnchecked = + checkbox.dataset.indeterminate === 'false' && + checkbox.dataset.checked === 'false'; + // The only time a click on the check-all checkbox should check all is + // when it was previously unchecked; otherwise, if the checkbox was + // either checked (all selected) or indeterminate (some selected), the + // click should clear all. + if (previouslyUnchecked) { + // Select all items + this._sortedItems.forEach( + (item: Contents.IModel) => (this.selection[item.path] = true) + ); + } else { + // Unselect all items + this.clearSelectedItems(); + } + this.update(); + } else { + const state = this.renderer.handleHeaderClick(header, event); + if (state) { + this.sort(state); + } } return; } @@ -1095,6 +1164,13 @@ export class DirListing extends Widget { return; } + // Do nothing if the double click is on a checkbox. (Otherwise a rapid + // check-uncheck on the checkbox will cause the adjacent file/folder to + // open, which is probably not what the user intended.) + if (this.isWithinCheckboxHitArea(event)) { + return; + } + // Stop the event propagation. event.preventDefault(); event.stopPropagation(); @@ -1129,7 +1205,7 @@ export class DirListing extends Widget { } for (let i = 0; i < length; i++) { let entry = event.dataTransfer?.items[i].webkitGetAsEntry(); - if (entry.isDirectory) { + if (entry?.isDirectory) { console.log('currently not supporting drag + drop for folders'); void showDialog({ title: this._trans.__('Error Uploading Folder'), @@ -1381,8 +1457,18 @@ export class DirListing extends Widget { const path = items[index].path; const selected = Object.keys(this.selection); + const isLeftClickOnCheckbox = + event.button === 0 && + // On Mac, a left-click with the ctrlKey is treated as a right-click. + !(IS_MAC && event.ctrlKey) && + this.isWithinCheckboxHitArea(event); + // Handle toggling. - if ((IS_MAC && event.metaKey) || (!IS_MAC && event.ctrlKey)) { + if ( + (IS_MAC && event.metaKey) || + (!IS_MAC && event.ctrlKey) || + isLeftClickOnCheckbox + ) { if (this.selection[path]) { delete this.selection[path]; } else { @@ -1737,7 +1823,7 @@ export namespace DirListing { /** * Toggleable columns. */ - export type ToggleableColumn = 'last_modified'; + export type ToggleableColumn = 'last_modified' | 'is_selected'; /** * A file contents model thunk. @@ -1824,6 +1910,20 @@ export namespace DirListing { */ getNameNode(node: HTMLElement): HTMLElement; + /** + * Get the checkbox input element node. + * + * Downstream interface implementations,such as jupyterlab-unfold, that + * don't support checkboxes should simply always return null for this + * function. + * + * @param node A node created by [[createItemNode]] or + * [[createHeaderItemNode]] + * + * @returns The checkbox node. + */ + getCheckboxNode: (node: HTMLElement) => HTMLInputElement | null; + /** * Create an appropriate drag image for an item. * @@ -1882,6 +1982,12 @@ export namespace DirListing { modified.classList.add(MODIFIED_ID_CLASS); narrow.classList.add(NARROW_ID_CLASS); narrow.textContent = '...'; + if (!hiddenColumns?.has?.('is_selected')) { + const checkboxWrapper = this.createCheckboxWrapperNode({ + alwaysVisible: true + }); + node.appendChild(checkboxWrapper); + } node.appendChild(name); node.appendChild(narrow); node.appendChild(modified); @@ -1985,6 +2091,10 @@ export namespace DirListing { icon.className = ITEM_ICON_CLASS; text.className = ITEM_TEXT_CLASS; modified.className = ITEM_MODIFIED_CLASS; + if (!hiddenColumns?.has?.('is_selected')) { + const checkboxWrapper = this.createCheckboxWrapperNode(); + node.appendChild(checkboxWrapper); + } node.appendChild(icon); node.appendChild(text); node.appendChild(modified); @@ -2003,6 +2113,43 @@ export namespace DirListing { return node; } + /** + * Creates a node containing a checkbox. + * + * We wrap the checkbox in a label element in order to increase its hit + * area. This is because the padding of the checkbox itself cannot be + * increased via CSS, as the CSS/form compatibility table at the following + * url from MDN shows: + * https://developer.mozilla.org/en-US/docs/Learn/Forms/Property_compatibility_table_for_form_controls#check_boxes_and_radio_buttons + * + * @param [options] + * @params options.alwaysVisible Should the checkbox be visible even when + * not hovered? + * @returns A new DOM node that contains a checkbox. + */ + createCheckboxWrapperNode(options?: { + alwaysVisible: boolean; + }): HTMLElement { + // Wrap the checkbox in a label element in order to increase its hit area. + const labelWrapper = document.createElement('label'); + labelWrapper.classList.add(CHECKBOX_WRAPPER_CLASS); + // The individual file checkboxes are visible on hover, but the header + // check-all checkbox is always visible. + if (options?.alwaysVisible) { + labelWrapper.classList.add('jp-mod-visible'); + } + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + // Prevent the user from clicking (via mouse, keyboard, or touch) the + // checkbox since other code handles the mouse and keyboard events and + // controls the checked state of the checkbox. + checkbox.addEventListener('click', event => { + event.preventDefault(); + }); + labelWrapper.appendChild(checkbox); + return labelWrapper; + } + /** * Update an item node to reflect the current state of a model. * @@ -2031,6 +2178,18 @@ export namespace DirListing { const iconContainer = DOMUtils.findElement(node, ITEM_ICON_CLASS); const text = DOMUtils.findElement(node, ITEM_TEXT_CLASS); const modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS); + const checkboxWrapper = DOMUtils.findElement( + node, + CHECKBOX_WRAPPER_CLASS + ); + + const showFileCheckboxes = !hiddenColumns?.has?.('is_selected'); + if (checkboxWrapper && !showFileCheckboxes) { + node.removeChild(checkboxWrapper); + } else if (showFileCheckboxes && !checkboxWrapper) { + const checkboxWrapper = this.createCheckboxWrapperNode(); + node.insertBefore(checkboxWrapper, iconContainer); + } if (hiddenColumns?.has?.('last_modified')) { modified.classList.add(MODIFIED_COLUMN_HIDDEN); @@ -2114,6 +2273,20 @@ export namespace DirListing { return DOMUtils.findElement(node, ITEM_TEXT_CLASS); } + /** + * Get the checkbox input element node. + * + * @param node A node created by [[createItemNode]] or + * [[createHeaderItemNode]] + * + * @returns The checkbox node. + */ + getCheckboxNode(node: HTMLElement): HTMLInputElement | null { + return node.querySelector( + `.${CHECKBOX_WRAPPER_CLASS} input[type=checkbox]` + ); + } + /** * Create a drag image for an item. * diff --git a/packages/filebrowser/src/model.ts b/packages/filebrowser/src/model.ts index 30a160b..85b63a6 100644 --- a/packages/filebrowser/src/model.ts +++ b/packages/filebrowser/src/model.ts @@ -11,6 +11,7 @@ import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; +import { IScore } from '@jupyterlab/ui-components'; import { ArrayExt, ArrayIterator, @@ -103,7 +104,7 @@ export class FileBrowserModel implements IDisposable { backoff: true, max: 300 * 1000 }, - standby: 'when-hidden' + standby: options.refreshStandby || 'when-hidden' }); } @@ -378,6 +379,10 @@ export class FileBrowserModel implements IDisposable { } const path = (value as ReadonlyJSONObject)['path'] as string; + // need to return to root path if preferred dir is set + if (path) { + await this.cd('/'); + } const localPath = manager.services.contents.localPath(path); await manager.services.contents.get(path); @@ -699,6 +704,11 @@ export namespace FileBrowserModel { */ refreshInterval?: number; + /** + * When the model stops polling the API. Defaults to `when-hidden`. + */ + refreshStandby?: Poll.Standby | (() => boolean | Poll.Standby); + /** * An optional state database. If provided, the model will restore which * folder was last opened when it is restored. @@ -764,7 +774,22 @@ export namespace TogglableHiddenFileBrowserModel { export class FilterFileBrowserModel extends TogglableHiddenFileBrowserModel { constructor(options: FilterFileBrowserModel.IOptions) { super(options); - this._filter = options.filter ? options.filter : model => true; + this._filter = + options.filter ?? + (model => { + return {}; + }); + this._filterDirectories = options.filterDirectories ?? true; + } + + /** + * Whether to filter directories. + */ + get filterDirectories(): boolean { + return this._filterDirectories; + } + set filterDirectories(value: boolean) { + this._filterDirectories = value; } /** @@ -774,20 +799,23 @@ export class FilterFileBrowserModel extends TogglableHiddenFileBrowserModel { */ items(): IIterator { return filter(super.items(), (value, index) => { - if (value.type === 'directory') { + if (!this._filterDirectories && value.type === 'directory') { return true; } else { - return this._filter(value); + const filtered = this._filter(value); + value.indices = filtered?.indices; + return !!filtered; } }); } - setFilter(filter: (value: Contents.IModel) => boolean) { + setFilter(filter: (value: Contents.IModel) => Partial | null): void { this._filter = filter; void this.refresh(); } - private _filter: (value: Contents.IModel) => boolean; + private _filter: (value: Contents.IModel) => Partial | null; + private _filterDirectories: boolean; } /** @@ -801,6 +829,11 @@ export namespace FilterFileBrowserModel { /** * Filter function on file browser item model */ - filter?: (value: Contents.IModel) => boolean; + filter?: (value: Contents.IModel) => Partial | null; + + /** + * Filter directories + */ + filterDirectories?: boolean; } } diff --git a/packages/filebrowser/src/opendialog.ts b/packages/filebrowser/src/opendialog.ts index 6dc7290..59f50b1 100644 --- a/packages/filebrowser/src/opendialog.ts +++ b/packages/filebrowser/src/opendialog.ts @@ -1,11 +1,12 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { Dialog } from '@jupyterlab/apputils'; +import { Dialog, setToolbar, ToolbarButton } from '@jupyterlab/apputils'; import { PathExt } from '@jupyterlab/coreutils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { Contents } from '@jupyterlab/services'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { IScore, newFolderIcon, refreshIcon } from '@jupyterlab/ui-components'; import { toArray } from '@lumino/algorithm'; import { PanelLayout, Widget } from '@lumino/widgets'; import { FileBrowser } from './browser'; @@ -52,7 +53,7 @@ export namespace FileDialog { /** * Filter function on file browser item model */ - filter?: (value: Contents.IModel) => boolean; + filter?: (value: Contents.IModel) => Partial | null; /** * The application language translator. @@ -78,7 +79,7 @@ export namespace FileDialog { const dialogOptions: Partial> = { title: options.title, buttons: [ - Dialog.cancelButton({ label: trans.__('Cancel') }), + Dialog.cancelButton(), Dialog.okButton({ label: trans.__('Select') }) @@ -107,7 +108,9 @@ export namespace FileDialog { ): Promise> { return getOpenFiles({ ...options, - filter: model => false + filter: model => { + return model.type === 'directory' ? {} : null; + } }); } } @@ -117,14 +120,17 @@ export namespace FileDialog { */ class OpenDialog extends Widget - implements Dialog.IBodyWidget { + implements Dialog.IBodyWidget +{ constructor( manager: IDocumentManager, - filter?: (value: Contents.IModel) => boolean, - translator?: ITranslator + filter?: (value: Contents.IModel) => Partial | null, + translator?: ITranslator, + filterDirectories?: boolean ) { super(); - translator = translator || nullTranslator; + translator = translator ?? nullTranslator; + const trans = translator.load('jupyterlab'); this.addClass(OPEN_DIALOG_CLASS); this._browser = Private.createFilteredFileBrowser( @@ -132,9 +138,39 @@ class OpenDialog manager, filter, {}, - translator + translator, + filterDirectories ); + // Add toolbar items + setToolbar(this._browser, (browser: FileBrowser) => [ + { + name: 'new-folder', + widget: new ToolbarButton({ + icon: newFolderIcon, + onClick: () => { + browser.createNewDirectory(); + }, + tooltip: trans.__('New Folder') + }) + }, + { + name: 'refresher', + widget: new ToolbarButton({ + icon: refreshIcon, + onClick: () => { + browser.model.refresh().catch(reason => { + console.error( + 'Failed to refresh file browser in open dialog.', + reason + ); + }); + }, + tooltip: trans.__('Refresh File List') + }) + } + ]); + // Build the sub widgets const layout = new PanelLayout(); layout.addWidget(this._browser); @@ -197,17 +233,19 @@ namespace Private { export const createFilteredFileBrowser = ( id: string, manager: IDocumentManager, - filter?: (value: Contents.IModel) => boolean, + filter?: (value: Contents.IModel) => Partial | null, options: IFileBrowserFactory.IOptions = {}, - translator?: ITranslator - ) => { + translator?: ITranslator, + filterDirectories?: boolean + ): FileBrowser => { translator = translator || nullTranslator; const model = new FilterFileBrowserModel({ manager, filter, translator, driveName: options.driveName, - refreshInterval: options.refreshInterval + refreshInterval: options.refreshInterval, + filterDirectories }); const widget = new FileBrowser({ id, diff --git a/packages/filebrowser/src/tokens.ts b/packages/filebrowser/src/tokens.ts index 7e9028b..ba4ea1c 100644 --- a/packages/filebrowser/src/tokens.ts +++ b/packages/filebrowser/src/tokens.ts @@ -6,14 +6,12 @@ import { IStateDB } from '@jupyterlab/statedb'; import { Token } from '@lumino/coreutils'; import { FileBrowser } from './browser'; -/* tslint:disable */ /** * The path tracker token. */ export const IFileBrowserFactory = new Token( '@jupyterlab/filebrowser:IFileBrowserFactory' ); -/* tslint:enable */ /** * The file browser factory interface. @@ -108,3 +106,10 @@ export namespace IFileBrowserFactory { state?: IStateDB | null; } } + +/** + * The token that indicates the default file browser commands are loaded. + */ +export const IFileBrowserCommands = new Token( + '@jupyterlab/filebrowser:IFileBrowserCommands' +); diff --git a/packages/filebrowser/src/upload.ts b/packages/filebrowser/src/upload.ts index dcd3b92..1096b58 100644 --- a/packages/filebrowser/src/upload.ts +++ b/packages/filebrowser/src/upload.ts @@ -1,13 +1,13 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { showErrorMessage, ToolbarButton } from '@jupyterlab/apputils'; +import { showErrorMessage } from '@jupyterlab/apputils'; import { ITranslator, nullTranslator, TranslationBundle } from '@jupyterlab/translation'; -import { fileUploadIcon } from '@jupyterlab/ui-components'; +import { fileUploadIcon, ToolbarButton } from '@jupyterlab/ui-components'; import { FileBrowserModel } from './model'; /** @@ -20,6 +20,7 @@ export class Uploader extends ToolbarButton { constructor(options: Uploader.IOptions) { super({ icon: fileUploadIcon, + label: options.label, onClick: () => { this._input.click(); }, @@ -85,6 +86,11 @@ export namespace Uploader { * The language translator. */ translator?: ITranslator; + + /** + * An optional label. + */ + label?: string; } } @@ -105,7 +111,7 @@ namespace Private { /** * Translate upload tooltip. */ - export function translateToolTip(translator?: ITranslator) { + export function translateToolTip(translator?: ITranslator): string { translator = translator || nullTranslator; const trans = translator.load('jupyterlab'); return trans.__('Upload Files'); diff --git a/packages/filebrowser/src/uploadstatus.tsx b/packages/filebrowser/src/uploadstatus.tsx index cac175f..da6b832 100644 --- a/packages/filebrowser/src/uploadstatus.tsx +++ b/packages/filebrowser/src/uploadstatus.tsx @@ -2,7 +2,7 @@ // Distributed under the terms of the Modified BSD License. // -import { VDomModel, VDomRenderer, WidgetTracker } from '@jupyterlab/apputils'; +import { WidgetTracker } from '@jupyterlab/apputils'; import { IChangedArgs } from '@jupyterlab/coreutils'; import { GroupItem, ProgressBar, TextItem } from '@jupyterlab/statusbar'; import { @@ -10,6 +10,7 @@ import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; +import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components'; import { ArrayExt } from '@lumino/algorithm'; import React from 'react'; import { FileBrowser, FileBrowserModel, IUploadModel } from '.'; @@ -86,7 +87,7 @@ export class FileUploadStatus extends VDomRenderer { /** * Render the FileUpload status. */ - render() { + render(): JSX.Element { const uploadPaths = this.model!.items; if (uploadPaths.length > 0) { const item = this.model!.items[0]; @@ -106,7 +107,7 @@ export class FileUploadStatus extends VDomRenderer { } } - dispose() { + dispose(): void { super.dispose(); this._tracker.currentChanged.disconnect(this._onBrowserChange); } @@ -146,7 +147,7 @@ export namespace FileUploadStatus { /** * The currently uploading items. */ - get items() { + get items(): IFileUploadItem[] { return this._items; } @@ -194,15 +195,15 @@ export namespace FileUploadStatus { this._items[idx].progress = uploads.newValue.progress * 100; } } else if (uploads.name === 'finish') { - const idx = ArrayExt.findFirstIndex( + const finishedItem = ArrayExt.findFirstValue( this._items, val => val.path === uploads.oldValue.path ); - if (idx !== -1) { - this._items[idx].complete = true; + if (finishedItem) { + finishedItem.complete = true; setTimeout(() => { - ArrayExt.removeAt(this._items, idx); + ArrayExt.removeFirstOf(this._items, finishedItem); this.stateChanged.emit(void 0); }, UPLOAD_COMPLETE_MESSAGE_MILLIS); } diff --git a/packages/filebrowser/style/base.css b/packages/filebrowser/style/base.css index ac22cf3..c7c2773 100644 --- a/packages/filebrowser/style/base.css +++ b/packages/filebrowser/style/base.css @@ -17,33 +17,34 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -.jp-FileBrowser { +.jp-FileBrowser .jp-SidePanel-content { display: flex; flex-direction: column; - color: var(--jp-ui-font-color1); - background: var(--jp-layout-color1); - /* 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); } .jp-FileBrowser-toolbar.jp-Toolbar { border-bottom: none; height: auto; - margin: 8px 12px 0px 12px; + margin: 8px 12px 0; box-shadow: none; - padding: 0px; + padding: 0; justify-content: flex-start; } +.jp-FileBrowser-Panel { + flex: 1 1 auto; + display: flex; + flex-direction: column; +} + .jp-BreadCrumbs { flex: 0 0 auto; - margin: 8px 12px 8px 12px; + margin: 8px 12px; } .jp-BreadCrumbs-item { - margin: 0px 2px; - padding: 0px 2px; + margin: 0 2px; + padding: 0 2px; border-radius: var(--jp-border-radius); cursor: pointer; } @@ -53,7 +54,7 @@ } .jp-BreadCrumbs-item:first-child { - margin-left: 0px; + margin-left: 0; } .jp-BreadCrumbs-item.jp-mod-dropTarget { @@ -65,34 +66,22 @@ | Buttons |----------------------------------------------------------------------------*/ -.jp-FileBrowser-toolbar.jp-Toolbar .jp-Toolbar-item { +.jp-FileBrowser-toolbar > .jp-Toolbar-item { flex: 0 0 auto; - padding-left: 0px; + padding-left: 0; padding-right: 2px; + height: var(--jp-private-filebrowser-button-height); } -.jp-FileBrowser-toolbar.jp-Toolbar .jp-ToolbarButtonComponent { +.jp-FileBrowser-toolbar > .jp-Toolbar-item .jp-ToolbarButtonComponent { width: 40px; } -.jp-FileBrowser-toolbar.jp-Toolbar - .jp-Toolbar-item:first-child - .jp-ToolbarButtonComponent { - width: 72px; - background: var(--jp-info-color2); -} - -.jp-FileBrowser-toolbar.jp-Toolbar - .jp-Toolbar-item:first-child - .jp-ToolbarButtonComponent:focus-visible { - background-color: var(--jp-accept-color-active, var(--jp-info-color1)); -} - -.jp-FileBrowser-toolbar.jp-Toolbar - .jp-Toolbar-item:first-child - .jp-ToolbarButtonComponent - .jp-icon3 { - fill: var(--jp-layout-color1); +.jp-FileBrowser-toolbar + > .jp-Toolbar-item + .jp-ToolbarButtonComponent[data-command='notebook:create-new'] { + width: 60px; + background: #f4f6f8; } /*----------------------------------------------------------------------------- @@ -112,9 +101,13 @@ } .jp-FileBrowser-filterBox { - padding: 0px; + padding: 0; flex: 0 0 auto; - margin: 8px 12px 0px 12px; + margin: 8px 12px 0; +} + +.jp-FileBrowser .lm-AccordionPanel > h3:first-child { + display: none; } /*----------------------------------------------------------------------------- @@ -136,15 +129,15 @@ flex: 0 0 auto; display: flex; flex-direction: row; + align-items: center; overflow: hidden; - border-top: var(--jp-border-width) solid var(--jp-border-color2); - border-bottom: var(--jp-border-width) solid var(--jp-border-color1); - box-shadow: var(--jp-toolbar-box-shadow); + border-top: 1px solid #e0e0e0; + border-bottom: 1px solid #e0e0e0; z-index: 2; } .jp-DirListing-headerItem { - padding: 4px 12px 2px 12px; + padding: 4px 12px 2px; font-weight: 500; } @@ -165,7 +158,7 @@ .jp-id-narrow { display: none; flex: 0 0 5px; - padding: 4px 4px; + padding: 4px; border-left: var(--jp-border-width) solid var(--jp-border-color2); text-align: right; color: var(--jp-border-color2); @@ -214,14 +207,48 @@ .jp-DirListing-item { display: flex; flex-direction: row; - padding: 4px 4px; - margin-left: 8px; - margin-right: 8px; + align-items: center; + padding: 4px 12px; + margin-bottom: 4px; + margin-top: 4px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; - border-right: 4px; +} + +.jp-DirListing-checkboxWrapper { + /* Increases hit area of checkbox. */ + padding: 4px; +} + +.jp-DirListing-header + .jp-DirListing-checkboxWrapper + + .jp-DirListing-headerItem { + padding-left: 4px; +} + +.jp-DirListing-content .jp-DirListing-checkboxWrapper { + position: relative; + left: -4px; + margin: -4px 0 -4px -8px; +} + +.jp-DirListing-checkboxWrapper.jp-mod-visible { + visibility: visible; +} + +/* For devices that support hovering, hide checkboxes until hovered, selected... +*/ +@media (hover: hover) { + .jp-DirListing-checkboxWrapper { + visibility: hidden; + } + + .jp-DirListing-item:hover .jp-DirListing-checkboxWrapper, + .jp-DirListing-item.jp-mod-selected .jp-DirListing-checkboxWrapper { + visibility: visible; + } } .jp-DirListing-item[data-is-dot] { @@ -229,9 +256,10 @@ } .jp-DirListing-item.jp-mod-selected { - /*color: var(--jp-ui-inverse-font-color1);*/ - background: #dfe5eb; - border-radius: 4px; + color: #000; + + /*background: var(--jp-brand-color1);*/ + background: #f4f6f8; } .jp-DirListing-item.jp-mod-dropTarget { @@ -266,8 +294,8 @@ border: none; } -.jp-DirListing-item.jp-mod-running .jp-DirListing-itemIcon:before { - color: var(--jp-success-color1); +.jp-DirListing-item.jp-mod-running .jp-DirListing-itemIcon::before { + color: var(--jp-brand-color1); content: '\25CF'; font-size: 8px; position: absolute; @@ -275,9 +303,8 @@ } .jp-DirListing-item.jp-mod-running.jp-mod-selected - .jp-DirListing-itemIcon:before { - /*color: var(--jp-ui-inverse-font-color1);*/ - color: orangered; + .jp-DirListing-itemIcon::before { + color: var(--jp-brand-color0); } .jp-DirListing-item.lm-mod-drag-image, @@ -288,7 +315,7 @@ width: 160px; background-color: var(--jp-ui-inverse-font-color2); box-shadow: var(--jp-elevation-z2); - border-radius: 0px; + border-radius: 0; color: var(--jp-ui-font-color1); transform: translateX(-40%) translateY(-58%); } diff --git a/packages/filebrowser/test/listing.spec.ts b/packages/filebrowser/test/listing.spec.ts new file mode 100644 index 0000000..828306a --- /dev/null +++ b/packages/filebrowser/test/listing.spec.ts @@ -0,0 +1,297 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import expect from 'expect'; +import { simulate } from 'simulate-event'; +import { toArray } from '@lumino/algorithm'; +import { Signal } from '@lumino/signaling'; +import { Widget } from '@lumino/widgets'; +import { DocumentManager } from '@jupyterlab/docmanager'; +import { DocumentRegistry } from '@jupyterlab/docregistry'; +import { Mock, signalToPromise } from '@jupyterlab/testutils'; +import { DirListing, FilterFileBrowserModel } from '../src'; + +// Returns the minimal args needed to create a new DirListing instance +const createOptionsForConstructor: () => DirListing.IOptions = () => ({ + model: new FilterFileBrowserModel({ + manager: new DocumentManager({ + registry: new DocumentRegistry(), + opener: { + open: () => { + /* noop */ + } + }, + manager: new Mock.ServiceManagerMock() + }) + }) +}); + +class TestDirListing extends DirListing { + updated = new Signal(this); + onUpdateRequest(...args: any[]) { + super.onUpdateRequest.apply(this, args); + // Allows us to spy on onUpdateRequest. + this.updated.emit(); + } +} + +describe('filebrowser/listing', () => { + describe('DirListing', () => { + describe('#constructor', () => { + it('should return new DirListing instance', () => { + const options = createOptionsForConstructor(); + const dirListing = new DirListing(options); + expect(dirListing).toBeInstanceOf(DirListing); + }); + }); + }); + + describe('checkboxes', () => { + let dirListing: TestDirListing; + + beforeEach(async () => { + const options = createOptionsForConstructor(); + + // Start with some files instead of empty before creating the DirListing. + // This makes it easier to test checking/unchecking because after the + // DirListing is created, whenever a file is added, the DirListing selects + // that file, which causes the file's checkbox to be checked. + await options.model.manager.newUntitled({ type: 'file' }); + await options.model.manager.newUntitled({ type: 'file' }); + + // Create the widget and mount it to the DOM. + dirListing = new TestDirListing(options); + Widget.attach(dirListing, document.body); + + // Wait for the widget to update its internal DOM state before running + // tests. + await signalToPromise(dirListing.updated); + }); + + afterEach(() => { + Widget.detach(dirListing); + }); + + describe('file/item checkbox', () => { + it('check initial conditions', async () => { + expect(toArray(dirListing.selectedItems())).toHaveLength(0); + expect(toArray(dirListing.sortedItems())).toHaveLength(2); + }); + + it('should be checked after item is selected', async () => { + const itemNode = dirListing.contentNode.children[0] as HTMLElement; + const checkbox = dirListing.renderer.getCheckboxNode!( + itemNode + ) as HTMLInputElement; + expect(checkbox.checked).toBe(false); + dirListing.selectNext(); + await signalToPromise(dirListing.updated); + expect(checkbox.checked).toBe(true); + }); + + it('should be unchecked after item is unselected', async () => { + const itemNode = dirListing.contentNode.children[0] as HTMLElement; + const checkbox = dirListing.renderer.getCheckboxNode!( + itemNode + ) as HTMLInputElement; + dirListing.selectNext(); + await signalToPromise(dirListing.updated); + expect(checkbox.checked).toBe(true); + // Selecting the next item unselects the first. + dirListing.selectNext(); + await signalToPromise(dirListing.updated); + expect(checkbox.checked).toBe(false); + }); + + it('should allow selecting multiple items', async () => { + const itemNodes = Array.from( + dirListing.contentNode.children + ) as HTMLElement[]; + // JSDOM doesn't render anything, which means that all the elements have + // zero dimensions, so this is needed in order for the DirListing + // mousedown handler to believe that the mousedown event is relevant. + itemNodes[0].getBoundingClientRect = (): any => ({ + left: 0, + right: 10, + top: 0, + bottom: 10 + }); + itemNodes[1].getBoundingClientRect = (): any => ({ + left: 0, + right: 10, + top: 10, + bottom: 20 + }); + const checkboxes = itemNodes.map(node => + dirListing.renderer.getCheckboxNode!(node) + ) as HTMLInputElement[]; + const items = toArray(dirListing.sortedItems()); + expect(dirListing.isSelected(items[0].name)).toBe(false); + expect(dirListing.isSelected(items[1].name)).toBe(false); + simulate(checkboxes[0], 'mousedown', { + clientX: 1, + clientY: 1 + }); + simulate(checkboxes[1], 'mousedown', { + clientX: 1, + clientY: 11 + }); + await signalToPromise(dirListing.updated); + expect(dirListing.isSelected(items[0].name)).toBe(true); + expect(dirListing.isSelected(items[1].name)).toBe(true); + }); + + it('should reflect multiple items selected', async () => { + const itemNodes = Array.from( + dirListing.contentNode.children + ) as HTMLElement[]; + const checkboxes = itemNodes.map(node => + dirListing.renderer.getCheckboxNode!(node) + ) as HTMLInputElement[]; + expect(checkboxes[0].checked).toBe(false); + expect(checkboxes[1].checked).toBe(false); + dirListing.selectNext(); + dirListing.selectNext(true); // true = keep existing selection + await signalToPromise(dirListing.updated); + expect(checkboxes[0].checked).toBe(true); + expect(checkboxes[1].checked).toBe(true); + }); + + // A double click on the item should open the item; however, a double + // click on the checkbox should only check/uncheck the box. + it('should not open item on double click', () => { + const itemNode = dirListing.contentNode.children[0] as HTMLElement; + const checkbox = dirListing.renderer.getCheckboxNode!( + itemNode + ) as HTMLInputElement; + const wasOpened = jest.fn(); + dirListing.onItemOpened.connect(wasOpened); + simulate(checkbox, 'dblclick'); + expect(wasOpened).not.toHaveBeenCalled(); + dirListing.onItemOpened.disconnect(wasOpened); + }); + + it('should not become unchecked due to right-click on selected item', async () => { + const itemNode = dirListing.contentNode.children[0] as HTMLElement; + itemNode.getBoundingClientRect = (): any => ({ + left: 0, + right: 10, + top: 0, + bottom: 10 + }); + const checkbox = dirListing.renderer.getCheckboxNode!( + itemNode + ) as HTMLInputElement; + const item = dirListing.sortedItems().next()!; + await dirListing.selectItemByName(item.name); + await signalToPromise(dirListing.updated); + expect(checkbox.checked).toBe(true); + expect(dirListing.isSelected(item.name)).toBe(true); + simulate(checkbox, 'mousedown', { + clientX: 1, + clientY: 1, + button: 2 + }); + await signalToPromise(dirListing.updated); + // Item is still selected and checkbox is still checked after + // right-click. + expect(dirListing.isSelected(item.name)).toBe(true); + expect(checkbox.checked).toBe(true); + }); + + // This essentially tests that preventDefault has been called on the click + // handler (which also handles keyboard and touch "clicks" in addition to + // mouse clicks). In other words, only the DirListing should check/uncheck + // the checkbox, not the browser's built-in default handler for the click. + it('should not get checked by the default action of a click', () => { + const itemNode = dirListing.contentNode.children[0] as HTMLElement; + const checkbox = dirListing.renderer.getCheckboxNode!( + itemNode + ) as HTMLInputElement; + expect(checkbox.checked).toBe(false); + simulate(checkbox, 'click', { bubbles: false }); + expect(checkbox.checked).toBe(false); + }); + }); + + describe('check-all checkbox', () => { + it('should be unchecked when the current directory is empty', async () => { + const { path } = await dirListing.model.manager.newUntitled({ + type: 'directory' + }); + await dirListing.model.cd(path); + await signalToPromise(dirListing.updated); + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + expect(headerCheckbox.checked).toBe(false); + expect(headerCheckbox!.indeterminate).toBe(false); + }); + + describe('when previously unchecked', () => { + it('check initial conditions', () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + expect(headerCheckbox.checked).toBe(false); + expect(headerCheckbox!.indeterminate).toBe(false); + expect(toArray(dirListing.selectedItems())).toHaveLength(0); + }); + it('should check all', async () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + simulate(headerCheckbox, 'click'); + await signalToPromise(dirListing.updated); + expect(toArray(dirListing.selectedItems())).toHaveLength(2); + }); + }); + + describe('when previously indeterminate', () => { + beforeEach(async () => { + dirListing.selectNext(); + await signalToPromise(dirListing.updated); + }); + it('check initial conditions', () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + expect(headerCheckbox.indeterminate).toBe(true); + expect(toArray(dirListing.selectedItems())).toHaveLength(1); + }); + it('should uncheck all', async () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + simulate(headerCheckbox, 'click'); + await signalToPromise(dirListing.updated); + expect(toArray(dirListing.selectedItems())).toHaveLength(0); + }); + }); + + describe('when previously checked', () => { + beforeEach(async () => { + dirListing.selectNext(true); + dirListing.selectNext(true); + await signalToPromise(dirListing.updated); + }); + it('check initial conditions', () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + expect(headerCheckbox.checked).toBe(true); + expect(headerCheckbox.indeterminate).toBe(false); + expect(toArray(dirListing.selectedItems())).toHaveLength(2); + }); + it('should uncheck all', async () => { + const headerCheckbox = dirListing.renderer.getCheckboxNode!( + dirListing.headerNode + ) as HTMLInputElement; + simulate(headerCheckbox, 'click'); + await signalToPromise(dirListing.updated); + expect(toArray(dirListing.selectedItems())).toHaveLength(0); + }); + }); + }); + }); +}); diff --git a/packages/filebrowser/test/model.spec.ts b/packages/filebrowser/test/model.spec.ts index f092616..056cbcb 100644 --- a/packages/filebrowser/test/model.spec.ts +++ b/packages/filebrowser/test/model.spec.ts @@ -236,8 +236,8 @@ describe('filebrowser/model', () => { }); describe('#refresh()', () => { - it('should refresh the contents', () => { - return model.refresh(); + it('should refresh the contents', async () => { + await expect(model.refresh()).resolves.not.toThrow(); }); }); @@ -321,7 +321,7 @@ describe('filebrowser/model', () => { }); describe('#download()', () => { - it('should download the file without error', () => { + it.skip('should download the file without error', () => { // TODO: how to test this? }); }); diff --git a/packages/filebrowser/test/openfiledialog.spec.ts b/packages/filebrowser/test/openfiledialog.spec.ts index f9d199e..b81e166 100644 --- a/packages/filebrowser/test/openfiledialog.spec.ts +++ b/packages/filebrowser/test/openfiledialog.spec.ts @@ -55,7 +55,7 @@ describe('@jupyterlab/filebrowser', () => { it('should accept filter option', () => { const model = new FilterFileBrowserModel({ manager, - filter: (model: Contents.IModel) => false + filter: (model: Contents.IModel) => null }); expect(model).toBeInstanceOf(FilterFileBrowserModel); }); @@ -75,10 +75,11 @@ describe('@jupyterlab/filebrowser', () => { expect(filteredItems.length).toBe(items.length); }); - it('should list all directories whatever the filter', async () => { + it('should list all directories if filterDirectories is false', async () => { const filteredModel = new FilterFileBrowserModel({ manager, - filter: (model: Contents.IModel) => false + filter: (model: Contents.IModel) => null, + filterDirectories: false }); await filteredModel.cd(); const model = new FileBrowserModel({ manager }); @@ -90,10 +91,25 @@ describe('@jupyterlab/filebrowser', () => { expect(filteredItems.length).toBe(folders.length); }); + it('should filter files and directories if filterDirectories is true', async () => { + const filteredModel = new FilterFileBrowserModel({ + manager, + filter: (model: Contents.IModel) => null, + filterDirectories: true + }); + await filteredModel.cd(); + const model = new FileBrowserModel({ manager }); + await model.cd(); + + const filteredItems = toArray(filteredModel.items()); + expect(filteredItems.length).toBe(0); + }); + it('should respect the filter', async () => { const filteredModel = new FilterFileBrowserModel({ manager, - filter: (model: Contents.IModel) => model.type === 'notebook' + filter: (model: Contents.IModel) => + model.type === 'notebook' ? {} : null }); await filteredModel.cd(); const model = new FileBrowserModel({ manager }); @@ -103,9 +119,7 @@ describe('@jupyterlab/filebrowser', () => { filteredModel.items() ) as Contents.IModel[]; const items = toArray(model.items()); - const shownItems = items.filter( - item => item.type === 'directory' || item.type === 'notebook' - ); + const shownItems = items.filter(item => item.type === 'notebook'); expect(filteredItems.length).toBe(shownItems.length); const notebooks = filteredItems.filter( item => item.type === 'notebook' @@ -138,7 +152,8 @@ describe('@jupyterlab/filebrowser', () => { manager, title: 'Select a notebook', host: node, - filter: (value: Contents.IModel) => value.type === 'notebook' + filter: (value: Contents.IModel) => + value.type === 'notebook' ? {} : null }); await acceptDialog(); @@ -161,7 +176,8 @@ describe('@jupyterlab/filebrowser', () => { manager, title: 'Select a notebook', host: node, - filter: (value: Contents.IModel) => value.type === 'notebook' + filter: (value: Contents.IModel) => + value.type === 'notebook' ? {} : null }); await waitForDialog(); diff --git a/packages/filebrowser/tsconfig.test.json b/packages/filebrowser/tsconfig.test.json index 8e2fb27..709ea0f 100644 --- a/packages/filebrowser/tsconfig.test.json +++ b/packages/filebrowser/tsconfig.test.json @@ -34,33 +34,6 @@ }, { "path": "../../testutils" - }, - { - "path": "../apputils" - }, - { - "path": "../coreutils" - }, - { - "path": "../docmanager" - }, - { - "path": "../docregistry" - }, - { - "path": "../services" - }, - { - "path": "../statedb" - }, - { - "path": "../statusbar" - }, - { - "path": "../translation" - }, - { - "path": "../ui-components" } ] } diff --git a/packages/fileeditor-extension/package.json b/packages/fileeditor-extension/package.json index b645ca2..cd0fec0 100644 --- a/packages/fileeditor-extension/package.json +++ b/packages/fileeditor-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/fileeditor-extension", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Editor Widget Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -37,30 +37,37 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/codeeditor": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/console": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/filebrowser": "^3.3.2", - "@jupyterlab/fileeditor": "^3.3.2", - "@jupyterlab/launcher": "^3.3.2", - "@jupyterlab/mainmenu": "^3.3.2", - "@jupyterlab/observables": "^4.3.2", - "@jupyterlab/settingregistry": "^3.3.2", - "@jupyterlab/statusbar": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/commands": "^1.12.0", - "@lumino/coreutils": "^1.5.3", - "@lumino/widgets": "^1.19.0" + "@codemirror/commands": "^6.0.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/codeeditor": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/completer": "^4.0.0-alpha.12", + "@jupyterlab/console": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/documentsearch": "^4.0.0-alpha.12", + "@jupyterlab/filebrowser": "^4.0.0-alpha.12", + "@jupyterlab/fileeditor": "^4.0.0-alpha.12", + "@jupyterlab/launcher": "^4.0.0-alpha.12", + "@jupyterlab/lsp": "^4.0.0-alpha.12", + "@jupyterlab/mainmenu": "^4.0.0-alpha.12", + "@jupyterlab/observables": "^5.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/settingregistry": "^4.0.0-alpha.12", + "@jupyterlab/statusbar": "^4.0.0-alpha.12", + "@jupyterlab/toc": "^6.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/algorithm": "^1.9.1", + "@lumino/commands": "^1.20.0", + "@lumino/coreutils": "^1.12.0", + "@lumino/widgets": "^1.33.0" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/completer-extension/schema/files.json b/packages/fileeditor-extension/schema/completer.json similarity index 100% rename from packages/completer-extension/schema/files.json rename to packages/fileeditor-extension/schema/completer.json diff --git a/packages/fileeditor-extension/schema/plugin.json b/packages/fileeditor-extension/schema/plugin.json index 7b9935d..d2ec05b 100644 --- a/packages/fileeditor-extension/schema/plugin.json +++ b/packages/fileeditor-extension/schema/plugin.json @@ -102,14 +102,6 @@ } ], "context": [ - { - "command": "fileeditor:create-console", - "selector": ".jp-FileEditor" - }, - { - "command": "fileeditor:markdown-preview", - "selector": ".jp-FileEditor" - }, { "command": "fileeditor:undo", "selector": ".jp-FileEditor", @@ -139,6 +131,16 @@ "command": "fileeditor:select-all", "selector": ".jp-FileEditor", "rank": 6 + }, + { + "command": "fileeditor:create-console", + "selector": ".jp-FileEditor", + "rank": 10 + }, + { + "command": "fileeditor:markdown-preview", + "selector": ".jp-FileEditor", + "rank": 11 } ] }, @@ -164,7 +166,6 @@ "matchBrackets": true, "readOnly": false, "rulers": [], - "showTrailingSpace": false, "tabSize": 4, "wordWrapColumn": 80, "showTrailingSpace": false diff --git a/packages/fileeditor-extension/src/commands.ts b/packages/fileeditor-extension/src/commands.ts index 481a55c..bdbf16d 100644 --- a/packages/fileeditor-extension/src/commands.ts +++ b/packages/fileeditor-extension/src/commands.ts @@ -1,30 +1,35 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import { JupyterFrontEnd } from '@jupyterlab/application'; import { Clipboard, ICommandPalette, ISessionContextDialogs, + MainAreaWidget, sessionContextDialogs, WidgetTracker } from '@jupyterlab/apputils'; -import { CodeEditor } from '@jupyterlab/codeeditor'; +import { + CodeEditor, + CodeViewerWidget, + IEditorServices +} from '@jupyterlab/codeeditor'; import { CodeMirrorEditor } from '@jupyterlab/codemirror'; +import { ICompletionProviderManager } from '@jupyterlab/completer'; import { IConsoleTracker } from '@jupyterlab/console'; import { MarkdownCodeBlocks, PathExt } from '@jupyterlab/coreutils'; import { IDocumentWidget } from '@jupyterlab/docregistry'; import { IFileBrowserFactory } from '@jupyterlab/filebrowser'; -import { FileEditor } from '@jupyterlab/fileeditor'; +import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor'; import { ILauncher } from '@jupyterlab/launcher'; -import { - IEditMenu, - IFileMenu, - IMainMenu, - IRunMenu, - IViewMenu -} from '@jupyterlab/mainmenu'; +import { IMainMenu } from '@jupyterlab/mainmenu'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { TranslationBundle } from '@jupyterlab/translation'; +import { + ITranslator, + nullTranslator, + TranslationBundle +} from '@jupyterlab/translation'; import { consoleIcon, copyIcon, @@ -36,15 +41,19 @@ import { textEditorIcon, undoIcon } from '@jupyterlab/ui-components'; +import { toArray } from '@lumino/algorithm'; import { CommandRegistry } from '@lumino/commands'; import { JSONObject, ReadonlyJSONObject, ReadonlyPartialJSONObject } from '@lumino/coreutils'; +import { selectAll } from '@codemirror/commands'; const autoClosingBracketsNotebook = 'notebook:toggle-autoclosing-brackets'; const autoClosingBracketsConsole = 'console:toggle-autoclosing-brackets'; +type wrappingMode = 'on' | 'off' | 'wordWrapColumn' | 'bounded'; + /** * The command IDs used by the fileeditor plugin. */ @@ -57,12 +66,19 @@ export namespace CommandIDs { export const lineNumbers = 'fileeditor:toggle-line-numbers'; + export const currentLineNumbers = 'fileeditor:toggle-current-line-numbers'; + export const lineWrap = 'fileeditor:toggle-line-wrap'; + export const currentLineWrap = 'fileeditor:toggle-current-line-wrap'; + export const changeTabs = 'fileeditor:change-tabs'; export const matchBrackets = 'fileeditor:toggle-match-brackets'; + export const currentMatchBrackets = + 'fileeditor:toggle-current-match-brackets'; + export const autoClosingBrackets = 'fileeditor:toggle-autoclosing-brackets'; export const autoClosingBracketsUniversal = @@ -72,6 +88,8 @@ export namespace CommandIDs { export const replaceSelection = 'fileeditor:replace-selection'; + export const restartConsole = 'fileeditor:restart-console'; + export const runCode = 'fileeditor:run-code'; export const runAllCode = 'fileeditor:run-all'; @@ -89,6 +107,12 @@ export namespace CommandIDs { export const paste = 'fileeditor:paste'; export const selectAll = 'fileeditor:select-all'; + + export const invokeCompleter = 'completer:invoke-file'; + + export const selectCompleter = 'completer:select-file'; + + export const openCodeViewer = 'code-viewer:open'; } export interface IFileTypeData extends ReadonlyJSONObject { @@ -216,59 +240,13 @@ export namespace Commands { id: string, isEnabled: () => boolean, tracker: WidgetTracker>, - browserFactory: IFileBrowserFactory - ): void { - // Add a command to change font size. - addChangeFontSizeCommand(commands, settingRegistry, trans, id); - - addLineNumbersCommand(commands, settingRegistry, trans, id, isEnabled); - - addWordWrapCommand(commands, settingRegistry, trans, id, isEnabled); - - addChangeTabsCommand(commands, settingRegistry, trans, id); - - addMatchBracketsCommand(commands, settingRegistry, trans, id, isEnabled); - - addAutoClosingBracketsCommand(commands, settingRegistry, trans, id); - - addReplaceSelectionCommand(commands, tracker, trans, isEnabled); - - addCreateConsoleCommand(commands, tracker, trans, isEnabled); - - addRunCodeCommand(commands, tracker, trans, isEnabled); - - addRunAllCodeCommand(commands, tracker, trans, isEnabled); - - addMarkdownPreviewCommand(commands, tracker, trans); - - // Add a command for creating a new text file. - addCreateNewCommand(commands, browserFactory, trans); - - // Add a command for creating a new Markdown file. - addCreateNewMarkdownCommand(commands, browserFactory, trans); - - addUndoCommand(commands, tracker, trans, isEnabled); - - addRedoCommand(commands, tracker, trans, isEnabled); - - addCutCommand(commands, tracker, trans, isEnabled); - - addCopyCommand(commands, tracker, trans, isEnabled); - - addPasteCommand(commands, tracker, trans, isEnabled); - - addSelectAllCommand(commands, tracker, trans, isEnabled); - } - - /** - * Add a command to change font size for File Editor - */ - export function addChangeFontSizeCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string + browserFactory: IFileBrowserFactory, + consoleTracker: IConsoleTracker | null, + sessionDialogs: ISessionContextDialogs | null ): void { + /** + * Add a command to change font size for File Editor + */ commands.addCommand(CommandIDs.changeFontSize, { execute: args => { const delta = Number(args['delta']); @@ -286,7 +264,7 @@ export namespace Commands { const currentSize = config.fontSize || cssSize; config.fontSize = currentSize + delta; return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -303,23 +281,15 @@ export namespace Commands { } } }); - } - /** - * Add the Line Numbers command - */ - export function addLineNumbersCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string, - isEnabled: () => boolean - ): void { + /** + * Add the Line Numbers command + */ commands.addCommand(CommandIDs.lineNumbers, { execute: () => { config.lineNumbers = !config.lineNumbers; return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -328,25 +298,32 @@ export namespace Commands { isToggled: () => config.lineNumbers, label: trans.__('Line Numbers') }); - } - /** - * Add the Word Wrap command - */ - export function addWordWrapCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string, - isEnabled: () => boolean - ): void { - type wrappingMode = 'on' | 'off' | 'wordWrapColumn' | 'bounded'; + commands.addCommand(CommandIDs.currentLineNumbers, { + label: trans.__('Show Line Numbers'), + execute: () => { + const widget = tracker.currentWidget; + if (!widget) { + return; + } + const lineNumbers = !widget.content.editor.getOption('lineNumbers'); + widget.content.editor.setOption('lineNumbers', lineNumbers); + }, + isEnabled, + isToggled: () => { + const widget = tracker.currentWidget; + return widget?.content.editor.getOption('lineNumbers') ?? false; + } + }); + /** + * Add the Word Wrap command + */ commands.addCommand(CommandIDs.lineWrap, { execute: args => { config.lineWrap = (args['mode'] as wrappingMode) || 'off'; return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -358,17 +335,29 @@ export namespace Commands { }, label: trans.__('Word Wrap') }); - } - /** - * Add command for changing tabs size or type in File Editor - */ - export function addChangeTabsCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string - ): void { + commands.addCommand(CommandIDs.currentLineWrap, { + label: trans.__('Wrap Words'), + execute: () => { + const widget = tracker.currentWidget; + if (!widget) { + return; + } + const oldValue = widget.content.editor.getOption('lineWrap'); + const newValue = oldValue === 'off' ? 'on' : 'off'; + widget.content.editor.setOption('lineWrap', newValue); + }, + isEnabled, + isToggled: () => { + const widget = tracker.currentWidget; + return widget?.content.editor.getOption('lineWrap') !== 'off' ?? false; + } + }); + + /** + * Add command for changing tabs size or type in File Editor + */ + commands.addCommand(CommandIDs.changeTabs, { label: args => { if (args.insertSpaces) { @@ -385,7 +374,7 @@ export namespace Commands { config.tabSize = (args['size'] as number) || 4; config.insertSpaces = !!args['insertSpaces']; return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -396,23 +385,15 @@ export namespace Commands { return config.insertSpaces === insertSpaces && config.tabSize === size; } }); - } - /** - * Add the Match Brackets command - */ - export function addMatchBracketsCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string, - isEnabled: () => boolean - ): void { + /** + * Add the Match Brackets command + */ commands.addCommand(CommandIDs.matchBrackets, { execute: () => { config.matchBrackets = !config.matchBrackets; return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -421,24 +402,34 @@ export namespace Commands { isEnabled, isToggled: () => config.matchBrackets }); - } - /** - * Add the Auto Close Brackets for Text Editor command - */ - export function addAutoClosingBracketsCommand( - commands: CommandRegistry, - settingRegistry: ISettingRegistry, - trans: TranslationBundle, - id: string - ): void { + commands.addCommand(CommandIDs.currentMatchBrackets, { + label: trans.__('Match Brackets'), + execute: () => { + const widget = tracker.currentWidget; + if (!widget) { + return; + } + const matchBrackets = !widget.content.editor.getOption('matchBrackets'); + widget.content.editor.setOption('matchBrackets', matchBrackets); + }, + isEnabled, + isToggled: () => { + const widget = tracker.currentWidget; + return widget?.content.editor.getOption('matchBrackets') ?? false; + } + }); + + /** + * Add the Auto Close Brackets for Text Editor command + */ commands.addCommand(CommandIDs.autoClosingBrackets, { execute: args => { config.autoClosingBrackets = !!( args['force'] ?? !config.autoClosingBrackets ); return settingRegistry - .set(id, 'editorConfig', (config as unknown) as JSONObject) + .set(id, 'editorConfig', config as unknown as JSONObject) .catch((reason: Error) => { console.error(`Failed to set ${id}: ${reason.message}`); }); @@ -475,17 +466,11 @@ export namespace Commands { commands.isToggled(autoClosingBracketsNotebook) || commands.isToggled(autoClosingBracketsConsole) }); - } - /** - * Add the replace selection for text editor command - */ - export function addReplaceSelectionCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add the replace selection for text editor command + */ + commands.addCommand(CommandIDs.replaceSelection, { execute: args => { const text: string = (args['text'] as string) || ''; @@ -498,17 +483,10 @@ export namespace Commands { isEnabled, label: trans.__('Replace Selection in Editor') }); - } - /** - * Add the Create Console for Editor command - */ - export function addCreateConsoleCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add the Create Console for Editor command + */ commands.addCommand(CommandIDs.createConsole, { execute: args => { const widget = tracker.currentWidget; @@ -523,17 +501,34 @@ export namespace Commands { icon: consoleIcon, label: trans.__('Create Console for Editor') }); - } - /** - * Add the Run Code command - */ - export function addRunCodeCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Restart the Console Kernel linked to the current Editor + */ + commands.addCommand(CommandIDs.restartConsole, { + execute: async () => { + const current = tracker.currentWidget?.content; + + if (!current || consoleTracker === null) { + return; + } + + const widget = consoleTracker.find( + widget => widget.sessionContext.session?.path === current.context.path + ); + if (widget) { + return (sessionDialogs || sessionContextDialogs).restart( + widget.sessionContext + ); + } + }, + label: trans.__('Restart Kernel'), + isEnabled: () => consoleTracker !== null && isEnabled() + }); + + /** + * Add the Run Code command + */ commands.addCommand(CommandIDs.runCode, { execute: () => { // Run the appropriate code, taking into account a ```fenced``` code block. @@ -592,19 +587,12 @@ export namespace Commands { } }, isEnabled, - label: trans.__('Run Code') + label: trans.__('Run Selected Code') }); - } - /** - * Add the Run All Code command - */ - export function addRunAllCodeCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add the Run All Code command + */ commands.addCommand(CommandIDs.runAllCode, { execute: () => { const widget = tracker.currentWidget?.content; @@ -639,16 +627,10 @@ export namespace Commands { isEnabled, label: trans.__('Run All Code') }); - } - /** - * Add markdown preview command - */ - export function addMarkdownPreviewCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle - ): void { + /** + * Add markdown preview command + */ commands.addCommand(CommandIDs.markdownPreview, { execute: () => { const widget = tracker.currentWidget; @@ -672,17 +654,56 @@ export namespace Commands { icon: markdownIcon, label: trans.__('Show Markdown Preview') }); - } - /** - * Add undo command - */ - export function addUndoCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add the New File command + * + * Defaults to Text/.txt if file type data is not specified + */ + commands.addCommand(CommandIDs.createNew, { + label: args => { + if (args.isPalette) { + return (args.paletteLabel as string) ?? trans.__('New Text File'); + } + return (args.launcherLabel as string) ?? trans.__('Text File'); + }, + caption: args => + (args.caption as string) ?? trans.__('Create a new text file'), + icon: args => + args.isPalette + ? undefined + : LabIcon.resolve({ + icon: (args.iconName as string) ?? textEditorIcon + }), + execute: args => { + const cwd = args.cwd || browserFactory.defaultBrowser.model.path; + return createNew( + commands, + cwd as string, + (args.fileExt as string) ?? 'txt' + ); + } + }); + + /** + * Add the New Markdown File command + */ + commands.addCommand(CommandIDs.createNewMarkdown, { + label: args => + args['isPalette'] + ? trans.__('New Markdown File') + : trans.__('Markdown File'), + caption: trans.__('Create a new markdown file'), + icon: args => (args['isPalette'] ? undefined : markdownIcon), + execute: args => { + const cwd = args['cwd'] || browserFactory.defaultBrowser.model.path; + return createNew(commands, cwd as string, 'md'); + } + }); + + /** + * Add undo command + */ commands.addCommand(CommandIDs.undo, { execute: () => { const widget = tracker.currentWidget?.content; @@ -710,17 +731,10 @@ export namespace Commands { icon: undoIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Undo') }); - } - /** - * Add redo command - */ - export function addRedoCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add redo command + */ commands.addCommand(CommandIDs.redo, { execute: () => { const widget = tracker.currentWidget?.content; @@ -748,17 +762,10 @@ export namespace Commands { icon: redoIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Redo') }); - } - /** - * Add cut command - */ - export function addCutCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add cut command + */ commands.addCommand(CommandIDs.cut, { execute: () => { const widget = tracker.currentWidget?.content; @@ -790,17 +797,10 @@ export namespace Commands { icon: cutIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Cut') }); - } - /** - * Add copy command - */ - export function addCopyCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add copy command + */ commands.addCommand(CommandIDs.copy, { execute: () => { const widget = tracker.currentWidget?.content; @@ -831,17 +831,10 @@ export namespace Commands { icon: copyIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Copy') }); - } - /** - * Add paste command - */ - export function addPasteCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add paste command + */ commands.addCommand(CommandIDs.paste, { execute: async () => { const widget = tracker.currentWidget?.content; @@ -865,17 +858,10 @@ export namespace Commands { icon: pasteIcon.bindprops({ stylesheet: 'menuItem' }), label: trans.__('Paste') }); - } - /** - * Add select all command - */ - export function addSelectAllCommand( - commands: CommandRegistry, - tracker: WidgetTracker>, - trans: TranslationBundle, - isEnabled: () => boolean - ): void { + /** + * Add select all command + */ commands.addCommand(CommandIDs.selectAll, { execute: () => { const widget = tracker.currentWidget?.content; @@ -885,13 +871,50 @@ export namespace Commands { } const editor = widget.editor as CodeMirrorEditor; - editor.execCommand('selectAll'); + editor.execCommand(selectAll); }, isEnabled: () => Boolean(isEnabled() && tracker.currentWidget?.content), label: trans.__('Select All') }); } + export function addCompleterCommands( + commands: CommandRegistry, + editorTracker: IEditorTracker, + manager: ICompletionProviderManager, + translator: ITranslator | null + ): void { + const trans = (translator ?? nullTranslator).load('jupyterlab'); + + commands.addCommand(CommandIDs.invokeCompleter, { + label: trans.__('Display the completion helper.'), + execute: () => { + const id = + editorTracker.currentWidget && editorTracker.currentWidget.id; + if (id) { + return manager.invoke(id); + } + } + }); + + commands.addCommand(CommandIDs.selectCompleter, { + label: trans.__('Select the completion suggestion.'), + execute: () => { + const id = + editorTracker.currentWidget && editorTracker.currentWidget.id; + if (id) { + return manager.select(id); + } + } + }); + + commands.addKeyBinding({ + command: CommandIDs.selectCompleter, + keys: ['Enter'], + selector: '.jp-FileEditor .jp-mod-completer-active' + }); + } + /** * Helper function to check if there is a text selection in the editor */ @@ -918,83 +941,24 @@ export namespace Commands { /** * Function to create a new untitled text file, given the current working directory. */ - function createNew( + async function createNew( commands: CommandRegistry, cwd: string, ext: string = 'txt' ) { - return commands - .execute('docmanager:new-untitled', { - path: cwd, - type: 'file', - ext - }) - .then(model => { - if (model != undefined) { - return commands.execute('docmanager:open', { - path: model.path, - factory: FACTORY - }); - } - }); - } - - /** - * Add the New File command - * - * Defaults to Text/.txt if file type data is not specified - */ - export function addCreateNewCommand( - commands: CommandRegistry, - browserFactory: IFileBrowserFactory, - trans: TranslationBundle - ): void { - commands.addCommand(CommandIDs.createNew, { - label: args => { - if (args.isPalette) { - return (args.paletteLabel as string) ?? trans.__('New Text File'); - } - return (args.launcherLabel as string) ?? trans.__('Text File'); - }, - caption: args => - (args.caption as string) ?? trans.__('Create a new text file'), - icon: args => - args.isPalette - ? undefined - : LabIcon.resolve({ - icon: (args.iconName as string) ?? textEditorIcon - }), - execute: args => { - const cwd = args.cwd || browserFactory.defaultBrowser.model.path; - return createNew( - commands, - cwd as string, - (args.fileExt as string) ?? 'txt' - ); - } - }); - } - - /** - * Add the New Markdown File command - */ - export function addCreateNewMarkdownCommand( - commands: CommandRegistry, - browserFactory: IFileBrowserFactory, - trans: TranslationBundle - ): void { - commands.addCommand(CommandIDs.createNewMarkdown, { - label: args => - args['isPalette'] - ? trans.__('New Markdown File') - : trans.__('Markdown File'), - caption: trans.__('Create a new markdown file'), - icon: args => (args['isPalette'] ? undefined : markdownIcon), - execute: args => { - const cwd = args['cwd'] || browserFactory.defaultBrowser.model.path; - return createNew(commands, cwd as string, 'md'); - } + const model = await commands.execute('docmanager:new-untitled', { + path: cwd, + type: 'file', + ext }); + if (model != undefined) { + const widget = (await commands.execute('docmanager:open', { + path: model.path, + factory: FACTORY + })) as unknown as IDocumentWidget; + widget.isUntitled = true; + return widget; + } } /** @@ -1165,31 +1129,43 @@ export namespace Commands { */ export function addMenuItems( menu: IMainMenu, - commands: CommandRegistry, tracker: WidgetTracker>, - trans: TranslationBundle, consoleTracker: IConsoleTracker | null, - sessionDialogs: ISessionContextDialogs | null + isEnabled: () => boolean ): void { // Add undo/redo hooks to the edit menu. - addUndoRedoToEditMenu(menu, tracker); + menu.editMenu.undoers.redo.add({ + id: CommandIDs.redo, + isEnabled + }); + menu.editMenu.undoers.undo.add({ + id: CommandIDs.undo, + isEnabled + }); // Add editor view options. - addEditorViewerToViewMenu(menu, tracker); + menu.viewMenu.editorViewers.toggleLineNumbers.add({ + id: CommandIDs.currentLineNumbers, + isEnabled + }); + menu.viewMenu.editorViewers.toggleMatchBrackets.add({ + id: CommandIDs.currentMatchBrackets, + isEnabled + }); + menu.viewMenu.editorViewers.toggleWordWrap.add({ + id: CommandIDs.currentLineWrap, + isEnabled + }); // Add a console creator the the file menu. - addConsoleCreatorToFileMenu(menu, commands, tracker, trans); + menu.fileMenu.consoleCreators.add({ + id: CommandIDs.createConsole, + isEnabled + }); // Add a code runner to the run menu. if (consoleTracker) { - addCodeRunnersToRunMenu( - menu, - commands, - tracker, - consoleTracker, - trans, - sessionDialogs - ); + addCodeRunnersToRunMenu(menu, consoleTracker); } } @@ -1210,111 +1186,85 @@ export namespace Commands { } /** - * Add File Editor undo and redo widgets to the Edit menu + * Add a File Editor code runner to the Run menu */ - export function addUndoRedoToEditMenu( + export function addCodeRunnersToRunMenu( menu: IMainMenu, - tracker: WidgetTracker> + consoleTracker: IConsoleTracker ): void { - menu.editMenu.undoers.add({ - tracker, - undo: widget => { - widget.content.editor.undo(); - }, - redo: widget => { - widget.content.editor.redo(); - } - } as IEditMenu.IUndoer>); - } - - /** - * Add a File Editor editor viewer to the View Menu - */ - export function addEditorViewerToViewMenu( - menu: IMainMenu, - tracker: WidgetTracker> - ): void { - menu.viewMenu.editorViewers.add({ - tracker, - toggleLineNumbers: widget => { - const lineNumbers = !widget.content.editor.getOption('lineNumbers'); - widget.content.editor.setOption('lineNumbers', lineNumbers); - }, - toggleWordWrap: widget => { - const oldValue = widget.content.editor.getOption('lineWrap'); - const newValue = oldValue === 'off' ? 'on' : 'off'; - widget.content.editor.setOption('lineWrap', newValue); - }, - toggleMatchBrackets: widget => { - const matchBrackets = !widget.content.editor.getOption('matchBrackets'); - widget.content.editor.setOption('matchBrackets', matchBrackets); - }, - lineNumbersToggled: widget => - widget.content.editor.getOption('lineNumbers'), - wordWrapToggled: widget => - widget.content.editor.getOption('lineWrap') !== 'off', - matchBracketsToggled: widget => - widget.content.editor.getOption('matchBrackets') - } as IViewMenu.IEditorViewer>); + const isEnabled = (current: IDocumentWidget) => + current.context && + !!consoleTracker.find( + widget => widget.sessionContext.session?.path === current.context.path + ); + menu.runMenu.codeRunners.restart.add({ + id: CommandIDs.restartConsole, + isEnabled + }); + menu.runMenu.codeRunners.run.add({ + id: CommandIDs.runCode, + isEnabled + }); + menu.runMenu.codeRunners.runAll.add({ + id: CommandIDs.runAllCode, + isEnabled + }); } - /** - * Add a File Editor console creator to the File menu - */ - export function addConsoleCreatorToFileMenu( - menu: IMainMenu, - commands: CommandRegistry, - tracker: WidgetTracker>, + export function addOpenCodeViewerCommand( + app: JupyterFrontEnd, + editorServices: IEditorServices, + tracker: WidgetTracker>, trans: TranslationBundle - ): void { - const createConsole: ( - widget: IDocumentWidget - ) => Promise = getCreateConsoleFunction(commands); - menu.fileMenu.consoleCreators.add({ - tracker, - createConsoleLabel: (n: number) => trans.__('Create Console for Editor'), - createConsole - } as IFileMenu.IConsoleCreator>); - } + ) { + const openCodeViewer = async (args: { + content: string; + label?: string; + mimeType?: string; + extension?: string; + widgetId?: string; + }): Promise => { + const func = editorServices.factoryService.newDocumentEditor; + const factory: CodeEditor.Factory = options => { + return func(options); + }; - /** - * Add a File Editor code runner to the Run menu - */ - export function addCodeRunnersToRunMenu( - menu: IMainMenu, - commands: CommandRegistry, - tracker: WidgetTracker>, - consoleTracker: IConsoleTracker, - trans: TranslationBundle, - sessionDialogs: ISessionContextDialogs | null - ): void { - menu.runMenu.codeRunners.add({ - tracker, - runLabel: (n: number) => trans.__('Run Code'), - runAllLabel: (n: number) => trans.__('Run All Code'), - restartAndRunAllLabel: (n: number) => - trans.__('Restart Kernel and Run All Code'), - isEnabled: current => - !!consoleTracker.find( - widget => widget.sessionContext.session?.path === current.context.path - ), - run: () => commands.execute(CommandIDs.runCode), - runAll: () => commands.execute(CommandIDs.runAllCode), - restartAndRunAll: current => { - const widget = consoleTracker.find( - widget => widget.sessionContext.session?.path === current.context.path + // Derive mimetype from extension + let mimetype = args.mimeType; + if (!mimetype && args.extension) { + mimetype = editorServices.mimeTypeService.getMimeTypeByFilePath( + `temp.${args.extension.replace(/\\.$/, '')}` ); - if (widget) { - return (sessionDialogs || sessionContextDialogs) - .restart(widget.sessionContext) - .then(restarted => { - if (restarted) { - void commands.execute(CommandIDs.runAllCode); - } - return restarted; - }); - } } - } as IRunMenu.ICodeRunner>); + + const widget = CodeViewerWidget.createCodeViewer({ + factory, + content: args.content, + mimeType: mimetype + }); + widget.title.label = args.label || trans.__('Code Viewer'); + widget.title.caption = widget.title.label; + + // Get the fileType based on the mimetype to determine the icon + const fileType = toArray(app.docRegistry.fileTypes()).find(fileType => { + return mimetype ? fileType.mimeTypes.includes(mimetype) : undefined; + }); + widget.title.icon = fileType?.icon ?? textEditorIcon; + + if (args.widgetId) { + widget.id = args.widgetId; + } + const main = new MainAreaWidget({ content: widget }); + await tracker.add(main); + app.shell.add(main, 'main'); + return widget; + }; + + app.commands.addCommand(CommandIDs.openCodeViewer, { + label: trans.__('Open Code Viewer'), + execute: (args: any) => { + return openCodeViewer(args); + } + }); } } diff --git a/packages/fileeditor-extension/src/index.ts b/packages/fileeditor-extension/src/index.ts index d0f0035..e938c20 100644 --- a/packages/fileeditor-extension/src/index.ts +++ b/packages/fileeditor-extension/src/index.ts @@ -15,27 +15,49 @@ import { ICommandPalette, ISessionContextDialogs, IToolbarWidgetRegistry, + MainAreaWidget, WidgetTracker } from '@jupyterlab/apputils'; -import { CodeEditor, IEditorServices } from '@jupyterlab/codeeditor'; +import { + CodeEditor, + CodeViewerWidget, + IEditorServices, + IPositionModel +} from '@jupyterlab/codeeditor'; +import { ICompletionProviderManager } from '@jupyterlab/completer'; import { IConsoleTracker } from '@jupyterlab/console'; import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { ISearchProviderRegistry } from '@jupyterlab/documentsearch'; import { IFileBrowserFactory } from '@jupyterlab/filebrowser'; import { FileEditor, + FileEditorAdapter, FileEditorFactory, + FileEditorSearchProvider, IEditorTracker, + LaTeXTableOfContentsFactory, + MarkdownTableOfContentsFactory, + PythonTableOfContentsFactory, TabSpaceStatus } from '@jupyterlab/fileeditor'; import { ILauncher } from '@jupyterlab/launcher'; +import { + ILSPCodeExtractorsManager, + ILSPDocumentConnectionManager, + ILSPFeatureManager +} from '@jupyterlab/lsp'; import { IMainMenu } from '@jupyterlab/mainmenu'; import { IObservableList } from '@jupyterlab/observables'; +import { Session } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { IStatusBar } from '@jupyterlab/statusbar'; +import { ITableOfContentsRegistry } from '@jupyterlab/toc'; import { ITranslator } from '@jupyterlab/translation'; +import { find, toArray } from '@lumino/algorithm'; import { JSONObject } from '@lumino/coreutils'; -import { Menu } from '@lumino/widgets'; -import { Commands, FACTORY, IFileTypeData } from './commands'; +import { Menu, Widget } from '@lumino/widgets'; + +import { CommandIDs, Commands, FACTORY, IFileTypeData } from './commands'; export { Commands } from './commands'; @@ -58,6 +80,7 @@ const plugin: JupyterFrontEndPlugin = { IMainMenu, ILayoutRestorer, ISessionContextDialogs, + ITableOfContentsRegistry, IToolbarWidgetRegistry ], provides: IEditorTracker, @@ -139,10 +162,70 @@ export const tabSpaceStatus: JupyterFrontEndPlugin = { } }; +/** + * Cursor position. + */ +const lineColStatus: JupyterFrontEndPlugin = { + id: '@jupyterlab/fileeditor-extension:cursor-position', + activate: ( + app: JupyterFrontEnd, + tracker: IEditorTracker, + positionModel: IPositionModel + ) => { + positionModel.addEditorProvider((widget: Widget | null) => + widget && tracker.has(widget) + ? (widget as IDocumentWidget).content.editor + : null + ); + }, + requires: [IEditorTracker, IPositionModel], + autoStart: true +}; + +const completerPlugin: JupyterFrontEndPlugin = { + id: '@jupyterlab/fileeditor-extension:completer', + requires: [IEditorTracker], + optional: [ICompletionProviderManager], + activate: activateFileEditorCompleterService, + autoStart: true +}; + +/** + * A plugin to search file editors + */ +const searchProvider: JupyterFrontEndPlugin = { + id: '@jupyterlab/fileeditor-extension:search', + requires: [ISearchProviderRegistry], + autoStart: true, + activate: (app: JupyterFrontEnd, registry: ISearchProviderRegistry) => { + registry.add('jp-fileeditorSearchProvider', FileEditorSearchProvider); + } +}; + +const languageServerPlugin: JupyterFrontEndPlugin = { + id: '@jupyterlab/fileeditor-extension:language-server', + requires: [ + IEditorTracker, + ILSPDocumentConnectionManager, + ILSPFeatureManager, + ILSPCodeExtractorsManager + ], + + activate: activateFileEditorLanguageServer, + autoStart: true +}; + /** * Export the plugins as default. */ -const plugins: JupyterFrontEndPlugin[] = [plugin, tabSpaceStatus]; +const plugins: JupyterFrontEndPlugin[] = [ + plugin, + lineColStatus, + completerPlugin, + languageServerPlugin, + searchProvider, + tabSpaceStatus +]; export default plugins; /** @@ -160,6 +243,7 @@ function activate( menu: IMainMenu | null, restorer: ILayoutRestorer | null, sessionDialogs: ISessionContextDialogs | null, + tocRegistry: ITableOfContentsRegistry | null, toolbarRegistry: IToolbarWidgetRegistry | null ): IEditorTracker { const id = plugin.id; @@ -185,6 +269,7 @@ function activate( editorServices, factoryOptions: { name: FACTORY, + label: trans.__('Editor'), fileTypes: ['markdown', '*'], // Explicitly add the markdown fileType so defaultFor: ['markdown', '*'], // it outranks the defaultRendered viewer. toolbarFactory, @@ -301,7 +386,36 @@ function activate( id, isEnabled, tracker, - browserFactory + browserFactory, + consoleTracker, + sessionDialogs + ); + + const codeViewerTracker = new WidgetTracker>( + { + namespace: 'codeviewer' + } + ); + + // Handle state restoration for code viewers + if (restorer) { + void restorer.restore(codeViewerTracker, { + command: CommandIDs.openCodeViewer, + args: widget => ({ + content: widget.content.content, + label: widget.content.title.label, + mimeType: widget.content.mimeType, + widgetId: widget.content.id + }), + name: widget => widget.content.id + }); + } + + Commands.addOpenCodeViewerCommand( + app, + editorServices, + codeViewerTracker, + trans ); // Add a launcher item if the launcher is available. @@ -314,14 +428,7 @@ function activate( } if (menu) { - Commands.addMenuItems( - menu, - commands, - tracker, - trans, - consoleTracker, - sessionDialogs - ); + Commands.addMenuItems(menu, tracker, consoleTracker, isEnabled); } getAvailableKernelFileTypes() @@ -350,5 +457,119 @@ function activate( console.error(reason.message); }); + if (tocRegistry) { + tocRegistry.add(new LaTeXTableOfContentsFactory(tracker)); + tocRegistry.add(new MarkdownTableOfContentsFactory(tracker)); + tocRegistry.add(new PythonTableOfContentsFactory(tracker)); + } + return tracker; } + +/** + * Activate the completer service for file editor. + */ +function activateFileEditorCompleterService( + app: JupyterFrontEnd, + editorTracker: IEditorTracker, + manager: ICompletionProviderManager | null, + translator: ITranslator | null +): void { + if (!manager) { + return; + } + + Commands.addCompleterCommands( + app.commands, + editorTracker, + manager, + translator + ); + const sessionManager = app.serviceManager.sessions; + + const _activeSessions = new Map(); + const updateCompleter = async ( + _: IEditorTracker, + widget: IDocumentWidget + ) => { + const completerContext = { + editor: widget.content.editor, + widget + }; + + await manager.updateCompleter(completerContext); + const onRunningChanged = ( + _: Session.IManager, + models: Session.IModel[] + ) => { + const oldSession = _activeSessions.get(widget.id); + // Search for a matching path. + const model = find(models, m => m.path === widget.context.path); + if (model) { + // If there is a matching path, but it is the same + // session as we previously had, do nothing. + if (oldSession && oldSession.id === model.id) { + return; + } + // Otherwise, dispose of the old session and reset to + // a new CompletionConnector. + if (oldSession) { + _activeSessions.delete(widget.id); + oldSession.dispose(); + } + const session = sessionManager.connectTo({ model }); + const newCompleterContext = { + editor: widget.content.editor, + widget, + session + }; + manager.updateCompleter(newCompleterContext).catch(console.error); + _activeSessions.set(widget.id, session); + } else { + // If we didn't find a match, make sure + // the connector is the contextConnector and + // dispose of any previous connection. + if (oldSession) { + _activeSessions.delete(widget.id); + oldSession.dispose(); + } + } + }; + + onRunningChanged(sessionManager, toArray(sessionManager.running())); + sessionManager.runningChanged.connect(onRunningChanged); + + widget.disposed.connect(() => { + sessionManager.runningChanged.disconnect(onRunningChanged); + const session = _activeSessions.get(widget.id); + if (session) { + _activeSessions.delete(widget.id); + session.dispose(); + } + }); + }; + editorTracker.widgetAdded.connect(updateCompleter); + manager.activeProvidersChanged.connect(() => { + editorTracker.forEach(editorWidget => { + updateCompleter(editorTracker, editorWidget).catch(console.error); + }); + }); +} + +function activateFileEditorLanguageServer( + app: JupyterFrontEnd, + editors: IEditorTracker, + connectionManager: ILSPDocumentConnectionManager, + featureManager: ILSPFeatureManager, + extractorManager: ILSPCodeExtractorsManager +): void { + editors.widgetAdded.connect(async (_, editor) => { + const adapter = new FileEditorAdapter(editor, { + connectionManager, + featureManager, + foreignCodeExtractorsManager: extractorManager, + docRegistry: app.docRegistry + }); + connectionManager.registerAdapter(editor.context.path, adapter); + }); +} diff --git a/packages/fileeditor-extension/style/index.css b/packages/fileeditor-extension/style/index.css index 205b177..cb6700e 100644 --- a/packages/fileeditor-extension/style/index.css +++ b/packages/fileeditor-extension/style/index.css @@ -6,14 +6,18 @@ /* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */ @import url('https://github.com/~@lumino/widgets/style/index.css'); @import url('https://github.com/~@jupyterlab/ui-components/style/index.css'); +@import url('https://github.com/~@jupyterlab/statusbar/style/index.css'); @import url('https://github.com/~@jupyterlab/apputils/style/index.css'); @import url('https://github.com/~@jupyterlab/codeeditor/style/index.css'); -@import url('https://github.com/~@jupyterlab/statusbar/style/index.css'); +@import url('https://github.com/~@jupyterlab/documentsearch/style/index.css'); @import url('https://github.com/~@jupyterlab/codemirror/style/index.css'); @import url('https://github.com/~@jupyterlab/docregistry/style/index.css'); @import url('https://github.com/~@jupyterlab/application/style/index.css'); +@import url('https://github.com/~@jupyterlab/completer/style/index.css'); @import url('https://github.com/~@jupyterlab/filebrowser/style/index.css'); +@import url('https://github.com/~@jupyterlab/toc/style/index.css'); @import url('https://github.com/~@jupyterlab/console/style/index.css'); +@import url('https://github.com/~@jupyterlab/lsp/style/index.css'); @import url('https://github.com/~@jupyterlab/fileeditor/style/index.css'); @import url('https://github.com/~@jupyterlab/launcher/style/index.css'); @import url('https://github.com/~@jupyterlab/mainmenu/style/index.css'); diff --git a/packages/fileeditor-extension/style/index.js b/packages/fileeditor-extension/style/index.js index ab0ebb9..6db4cbd 100644 --- a/packages/fileeditor-extension/style/index.js +++ b/packages/fileeditor-extension/style/index.js @@ -6,14 +6,18 @@ /* 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/statusbar/style/index.js'; import '@jupyterlab/apputils/style/index.js'; import '@jupyterlab/codeeditor/style/index.js'; -import '@jupyterlab/statusbar/style/index.js'; +import '@jupyterlab/documentsearch/style/index.js'; import '@jupyterlab/codemirror/style/index.js'; import '@jupyterlab/docregistry/style/index.js'; import '@jupyterlab/application/style/index.js'; +import '@jupyterlab/completer/style/index.js'; import '@jupyterlab/filebrowser/style/index.js'; +import '@jupyterlab/toc/style/index.js'; import '@jupyterlab/console/style/index.js'; +import '@jupyterlab/lsp/style/index.js'; import '@jupyterlab/fileeditor/style/index.js'; import '@jupyterlab/launcher/style/index.js'; import '@jupyterlab/mainmenu/style/index.js'; diff --git a/packages/fileeditor-extension/tsconfig.json b/packages/fileeditor-extension/tsconfig.json index b166ae0..498da32 100644 --- a/packages/fileeditor-extension/tsconfig.json +++ b/packages/fileeditor-extension/tsconfig.json @@ -18,6 +18,9 @@ { "path": "../codemirror" }, + { + "path": "../completer" + }, { "path": "../console" }, @@ -27,6 +30,9 @@ { "path": "../docregistry" }, + { + "path": "../documentsearch" + }, { "path": "../filebrowser" }, @@ -36,18 +42,27 @@ { "path": "../launcher" }, + { + "path": "../lsp" + }, { "path": "../mainmenu" }, { "path": "../observables" }, + { + "path": "../services" + }, { "path": "../settingregistry" }, { "path": "../statusbar" }, + { + "path": "../toc" + }, { "path": "../translation" }, diff --git a/packages/fileeditor/.vscode/launch.json b/packages/fileeditor/.vscode/launch.json new file mode 100644 index 0000000..66fb4b8 --- /dev/null +++ b/packages/fileeditor/.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/fileeditor/babel.config.js b/packages/fileeditor/babel.config.js index 8b5c764..bf69a46 100644 --- a/packages/fileeditor/babel.config.js +++ b/packages/fileeditor/babel.config.js @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + module.exports = require('@jupyterlab/testutils/lib/babel.config'); diff --git a/packages/fileeditor/jest.config.js b/packages/fileeditor/jest.config.js index 178440a..64773dc 100644 --- a/packages/fileeditor/jest.config.js +++ b/packages/fileeditor/jest.config.js @@ -1,2 +1,7 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const func = require('@jupyterlab/testutils/lib/jest-config'); module.exports = func(__dirname); diff --git a/packages/fileeditor/package.json b/packages/fileeditor/package.json index 1b59837..e29814e 100644 --- a/packages/fileeditor/package.json +++ b/packages/fileeditor/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/fileeditor", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Editor Widget", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -23,9 +23,7 @@ "lib": "lib/" }, "files": [ - "lib/*.d.ts", - "lib/*.js.map", - "lib/*.js", + "lib/**/*.{d.ts,js,js.map}", "style/*.css", "style/index.js" ], @@ -41,25 +39,30 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/codeeditor": "^3.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/statusbar": "^3.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/coreutils": "^1.5.3", - "@lumino/messaging": "^1.4.3", - "@lumino/widgets": "^1.19.0", - "react": "^17.0.1" + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/codeeditor": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/documentsearch": "^4.0.0-alpha.12", + "@jupyterlab/lsp": "^4.0.0-alpha.12", + "@jupyterlab/statusbar": "^4.0.0-alpha.12", + "@jupyterlab/toc": "^6.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/coreutils": "^1.12.0", + "@lumino/messaging": "^1.10.1", + "@lumino/widgets": "^1.33.0", + "react": "^17.0.1", + "regexp-match-indices": "^1.0.2" }, "devDependencies": { - "@jupyterlab/testutils": "^3.3.2", + "@jupyterlab/testutils": "^4.0.0-alpha.12", "@types/jest": "^26.0.10", "jest": "^26.4.2", "rimraf": "~3.0.0", "ts-jest": "^26.3.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/fileeditor/src/fileeditorlspadapter.ts b/packages/fileeditor/src/fileeditorlspadapter.ts new file mode 100644 index 0000000..86f701f --- /dev/null +++ b/packages/fileeditor/src/fileeditorlspadapter.ts @@ -0,0 +1,191 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { CodeEditor } from '@jupyterlab/codeeditor'; +import { CodeMirrorEditor } from '@jupyterlab/codemirror'; +import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { + IAdapterOptions, + IVirtualPosition, + VirtualDocument, + WidgetLSPAdapter +} from '@jupyterlab/lsp'; + +import { FileEditor } from './widget'; + +export interface IFileEditorAdapterOptions extends IAdapterOptions { + /** + * The document registry instance. + */ + docRegistry: DocumentRegistry; +} + +export class FileEditorAdapter extends WidgetLSPAdapter< + IDocumentWidget +> { + constructor( + editorWidget: IDocumentWidget, + options: IFileEditorAdapterOptions + ) { + const { docRegistry, ...others } = options; + super(editorWidget, others); + this.editor = editorWidget.content; + this._docRegistry = docRegistry; + this.ready = new Promise((resolve, reject) => { + this.initOnceReady().then(resolve).catch(reject); + }); + + // Dispose the adapter when the editor is disposed. + editorWidget.disposed.connect(() => this.dispose()); + } + + /** + * The wrapped `FileEditor` widget. + */ + readonly editor: FileEditor; + + /** + * Get current path of the document. + */ + get documentPath(): string { + return this.widget.context.path; + } + + /** + * Get the mime type of the document. + */ + get mimeType(): string { + const codeMirrorMimeType = this.editor.model.mimeType; + const contentsModel = this.editor.context.contentsModel; + + // when MIME type is not known it defaults to 'text/plain', + // so if it is different we can accept it as it is + if (codeMirrorMimeType != 'text/plain') { + return codeMirrorMimeType; + } else if (contentsModel) { + // a script that does not have a MIME type known by the editor + // (no syntax highlight mode), can still be known by the document + // registry (and this is arguably easier to extend). + let fileType = this._docRegistry.getFileTypeForModel(contentsModel); + return fileType.mimeTypes[0]; + } else { + // "text/plain" this is + return codeMirrorMimeType; + } + } + + /** + * Get the file extension of the document. + */ + get languageFileExtension(): string { + let parts = this.documentPath.split('.'); + return parts[parts.length - 1]; + } + + /** + * Get the CM editor + */ + get ceEditor(): CodeMirrorEditor { + return this.editor.editor as CodeMirrorEditor; + } + + /** + * Get the activated CM editor. + */ + get activeEditor(): CodeEditor.IEditor { + return this.editor.editor; + } + + /** + * Get the inner HTMLElement of the document widget. + */ + get wrapperElement(): HTMLElement { + return this.widget.node; + } + + /** + * Get current path of the document. + */ + get path(): string { + return this.widget.context.path; + } + + /** + * Get the list of CM editors in the document, there is only one editor + * in the case of file editor. + */ + get editors(): { ceEditor: CodeEditor.IEditor; type: string }[] { + return [{ ceEditor: this.editor.editor, type: 'code' }]; + } + + /** + * Generate the virtual document associated with the document. + */ + createVirtualDocument(): VirtualDocument { + return new VirtualDocument({ + language: this.language, + foreignCodeExtractors: this.options.foreignCodeExtractorsManager, + path: this.documentPath, + fileExtension: this.languageFileExtension, + // notebooks are continuous, each cell is dependent on the previous one + standalone: true, + // notebooks are not supported by LSP servers + hasLspSupportedFile: true + }); + } + + /** + * Get the index of editor from the cursor position in the virtual + * document. Since there is only one editor, this method always return + * 0 + * + * @param position - the position of cursor in the virtual document. + * @return {number} - index of the virtual editor + */ + getEditorIndexAt(position: IVirtualPosition): number { + return 0; + } + + /** + * Get the index of input editor + * + * @param ceEditor - instance of the code editor + */ + getEditorIndex(ceEditor: CodeEditor.IEditor): number { + return 0; + } + + /** + * Get the wrapper of input editor. + * + * @param ceEditor + * @return {HTMLElement} + */ + getEditorWrapper(ceEditor: CodeEditor.IEditor): HTMLElement { + return this.wrapperElement; + } + + /** + * Initialization function called once the editor and the LSP connection + * manager is ready. This function will create the virtual document and + * connect various signals. + */ + protected async initOnceReady(): Promise { + if (!this.editor.context.isReady) { + await this.editor.context.ready; + } + await this.connectionManager.ready; + this.initVirtual(); + + // connect the document, but do not open it as the adapter will handle this + // after registering all features + this.connectDocument(this.virtualDocument, false).catch(console.warn); + + this.editor.model.mimeTypeChanged.connect(this.reloadConnection, this); + } + + /** + * The document registry instance. + */ + private readonly _docRegistry: DocumentRegistry; +} diff --git a/packages/fileeditor/src/index.ts b/packages/fileeditor/src/index.ts index 328fa4a..30d6574 100644 --- a/packages/fileeditor/src/index.ts +++ b/packages/fileeditor/src/index.ts @@ -5,6 +5,9 @@ * @module fileeditor */ +export * from './fileeditorlspadapter'; +export * from './searchprovider'; export * from './tabspacestatus'; +export * from './toc'; export * from './tokens'; export * from './widget'; diff --git a/packages/fileeditor/src/searchprovider.ts b/packages/fileeditor/src/searchprovider.ts new file mode 100644 index 0000000..37239bd --- /dev/null +++ b/packages/fileeditor/src/searchprovider.ts @@ -0,0 +1,79 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { MainAreaWidget } from '@jupyterlab/apputils'; +import { + CodeMirrorEditor, + CodeMirrorSearchProvider +} from '@jupyterlab/codemirror'; +import { ISearchProvider } from '@jupyterlab/documentsearch'; +import { ITranslator } from '@jupyterlab/translation'; +import { Widget } from '@lumino/widgets'; +import { FileEditor } from './widget'; + +/** + * Helper type + */ +export type FileEditorPanel = MainAreaWidget; + +/** + * File editor search provider + */ +export class FileEditorSearchProvider + extends CodeMirrorSearchProvider + implements ISearchProvider +{ + /** + * Constructor + * @param widget File editor panel + */ + constructor(widget: FileEditorPanel) { + super(widget.content.editor as CodeMirrorEditor); + } + + /** + * Instantiate a search provider for the widget. + * + * #### Notes + * The widget provided is always checked using `isApplicable` before calling + * this factory. + * + * @param widget The widget to search on + * @param translator [optional] The translator object + * + * @returns The search provider on the widget + */ + static createNew( + widget: FileEditorPanel, + translator?: ITranslator + ): ISearchProvider { + return new FileEditorSearchProvider(widget); + } + + /** + * Report whether or not this provider has the ability to search on the given object + */ + static isApplicable(domain: Widget): domain is FileEditorPanel { + return ( + domain instanceof MainAreaWidget && + domain.content instanceof FileEditor && + domain.content.editor instanceof CodeMirrorEditor + ); + } + + /** + * Get an initial query value if applicable so that it can be entered + * into the search box as an initial query + * + * @returns Initial value used to populate the search box. + */ + getInitialQuery(): string { + const cm = this.editor as CodeMirrorEditor; + const selection = cm.state.sliceDoc( + cm.state.selection.main.from, + cm.state.selection.main.to + ); + // if there are newlines, just return empty string + return selection.search(/\r?\n|\r/g) === -1 ? selection : ''; + } +} diff --git a/packages/fileeditor/src/tabspacestatus.tsx b/packages/fileeditor/src/tabspacestatus.tsx index a304c14..97edcad 100644 --- a/packages/fileeditor/src/tabspacestatus.tsx +++ b/packages/fileeditor/src/tabspacestatus.tsx @@ -1,7 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { VDomModel, VDomRenderer } from '@jupyterlab/apputils'; import { CodeEditor } from '@jupyterlab/codeeditor'; import { clickedItem, @@ -11,6 +10,7 @@ import { TextItem } from '@jupyterlab/statusbar'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; +import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components'; import { Menu } from '@lumino/widgets'; import React from 'react'; diff --git a/packages/fileeditor/src/toc/factory.ts b/packages/fileeditor/src/toc/factory.ts new file mode 100644 index 0000000..0d730fa --- /dev/null +++ b/packages/fileeditor/src/toc/factory.ts @@ -0,0 +1,72 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { + TableOfContents, + TableOfContentsFactory, + TableOfContentsModel +} from '@jupyterlab/toc'; +import { FileEditor } from '../widget'; + +/** + * Interface describing a file editor heading. + */ +export interface IEditorHeading extends TableOfContents.IHeading { + /** + * Heading line number. + */ + line: number; +} + +/** + * Base table of contents model factory for file editor + */ +export abstract class EditorTableOfContentsFactory extends TableOfContentsFactory< + IDocumentWidget +> { + /** + * 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: IDocumentWidget, + configuration?: TableOfContents.IConfig + ): TableOfContentsModel< + IEditorHeading, + IDocumentWidget + > { + const model = super.createNew( + widget, + configuration + ) as TableOfContentsModel< + IEditorHeading, + IDocumentWidget + >; + + const onActiveHeadingChanged = ( + model: TableOfContentsModel< + IEditorHeading, + IDocumentWidget + >, + heading: IEditorHeading | null + ) => { + if (heading) { + widget.content.editor.setCursorPosition({ + line: heading.line, + column: 0 + }); + } + }; + + model.activeHeadingChanged.connect(onActiveHeadingChanged); + widget.disposed.connect(() => { + model.activeHeadingChanged.disconnect(onActiveHeadingChanged); + }); + + return model; + } +} diff --git a/packages/fileeditor/src/toc/index.ts b/packages/fileeditor/src/toc/index.ts new file mode 100644 index 0000000..8cbe14b --- /dev/null +++ b/packages/fileeditor/src/toc/index.ts @@ -0,0 +1,7 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +export * from './factory'; +export * from './latex'; +export * from './markdown'; +export * from './python'; diff --git a/packages/fileeditor/src/toc/latex.ts b/packages/fileeditor/src/toc/latex.ts new file mode 100644 index 0000000..52599c9 --- /dev/null +++ b/packages/fileeditor/src/toc/latex.ts @@ -0,0 +1,145 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { + TableOfContents, + TableOfContentsModel, + TableOfContentsUtils +} from '@jupyterlab/toc'; +import { Widget } from '@lumino/widgets'; +import { FileEditor } from '../widget'; +import { EditorTableOfContentsFactory, IEditorHeading } from './factory'; + +/** + * 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 +}; + +/** + * Regular expression to create the outline + */ +const SECTIONS = /^\s*\\(section|subsection|subsubsection){(.+)}/; + +/** + * Table of content model for LaTeX files. + */ +export class LaTeXTableOfContentsModel extends TableOfContentsModel< + IEditorHeading, + IDocumentWidget +> { + /** + * 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="..."]` + */ + get documentType(): string { + return 'latex'; + } + + /** + * List of configuration options supported by the model. + */ + get supportedOptions(): (keyof TableOfContents.IConfig)[] { + return ['maximalDepth', 'numberHeaders']; + } + + /** + * Produce the headings for a document. + * + * @returns The list of new headings or `null` if nothing needs to be updated. + */ + protected getHeadings(): Promise { + if (!this.isActive) { + return Promise.resolve(null); + } + + // Split the text into lines: + const lines = this.widget.content.model.value.text.split( + '\n' + ) as Array; + + const levels = new Array(); + let previousLevel = levels.length; + const headings = new Array(); + for (let i = 0; i < lines.length; i++) { + const match = lines[i].match(SECTIONS); + if (match) { + const level = LATEX_LEVELS[match[1]]; + if (level <= this.configuration.maximalDepth) { + const prefix = TableOfContentsUtils.getPrefix( + level, + previousLevel, + levels, + { + ...this.configuration, + // Force base numbering and numbering first level + baseNumbering: 1, + numberingH1: true + } + ); + previousLevel = level; + + headings.push({ + text: match[2], + prefix: prefix, + level, + line: i + }); + } + } + } + return Promise.resolve(headings); + } +} + +/** + * Table of content model factory for LaTeX files. + */ +export class LaTeXTableOfContentsFactory extends EditorTableOfContentsFactory { + /** + * Whether the factory can handle the widget or not. + * + * @param widget - widget + * @returns boolean indicating a ToC can be generated + */ + isApplicable(widget: Widget): boolean { + const isApplicable = super.isApplicable(widget); + + if (isApplicable) { + let mime = (widget as any).content?.model?.mimeType; + return mime && (mime === 'text/x-latex' || mime === 'text/x-stex'); + } + return false; + } + + /** + * 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 + */ + protected _createNew( + widget: IDocumentWidget, + configuration?: TableOfContents.IConfig + ): LaTeXTableOfContentsModel { + return new LaTeXTableOfContentsModel(widget, configuration); + } +} diff --git a/packages/fileeditor/src/toc/markdown.ts b/packages/fileeditor/src/toc/markdown.ts new file mode 100644 index 0000000..fb9c54b --- /dev/null +++ b/packages/fileeditor/src/toc/markdown.ts @@ -0,0 +1,87 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { + TableOfContents, + TableOfContentsModel, + TableOfContentsUtils +} from '@jupyterlab/toc'; +import { Widget } from '@lumino/widgets'; +import { FileEditor } from '../widget'; +import { EditorTableOfContentsFactory, IEditorHeading } from './factory'; + +/** + * Table of content model for Markdown files. + */ +export class MarkdownTableOfContentsModel extends TableOfContentsModel< + IEditorHeading, + IDocumentWidget +> { + /** + * 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="..."]` + */ + get documentType(): string { + return 'markdown'; + } + + /** + * Produce the headings for a document. + * + * @returns The list of new headings or `null` if nothing needs to be updated. + */ + protected getHeadings(): Promise { + if (!this.isActive) { + return Promise.resolve(null); + } + + const content = this.widget.content.model.value.text; + + const headings = TableOfContentsUtils.Markdown.getHeadings(content, { + ...this.configuration, + // Force removing numbering as they cannot be displayed + // in the document + numberHeaders: false + }); + return Promise.resolve(headings); + } +} + +/** + * Table of content model factory for Markdown files. + */ +export class MarkdownTableOfContentsFactory extends EditorTableOfContentsFactory { + /** + * Whether the factory can handle the widget or not. + * + * @param widget - widget + * @returns boolean indicating a ToC can be generated + */ + isApplicable(widget: Widget): boolean { + const isApplicable = super.isApplicable(widget); + + if (isApplicable) { + let mime = (widget as any).content?.model?.mimeType; + return mime && TableOfContentsUtils.Markdown.isMarkdown(mime); + } + return false; + } + + /** + * 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 + */ + protected _createNew( + widget: IDocumentWidget, + configuration?: TableOfContents.IConfig + ): MarkdownTableOfContentsModel { + return new MarkdownTableOfContentsModel(widget, configuration); + } +} diff --git a/packages/fileeditor/src/toc/python.ts b/packages/fileeditor/src/toc/python.ts new file mode 100644 index 0000000..cc110c3 --- /dev/null +++ b/packages/fileeditor/src/toc/python.ts @@ -0,0 +1,143 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +/*eslint no-invalid-regexp: ["error", { "allowConstructorFlags": ["d"] }]*/ + +import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; +import { TableOfContents, TableOfContentsModel } from '@jupyterlab/toc'; +import { Widget } from '@lumino/widgets'; +import { FileEditor } from '../widget'; +import { EditorTableOfContentsFactory, IEditorHeading } from './factory'; + +/** + * Regular expression to create the outline + */ +let KEYWORDS: RegExp; +try { + // https://github.com/tc39/proposal-regexp-match-indices was accepted + // in May 2021 (https://github.com/tc39/proposals/blob/main/finished-proposals.md) + // So we will fallback to the polyfill regexp-match-indices if not available + KEYWORDS = new RegExp('^\\s*(class |def |from |import )', 'd'); +} catch { + KEYWORDS = new RegExp('^\\s*(class |def |from |import )'); +} + +/** + * Table of content model for Python files. + */ +export class PythonTableOfContentsModel extends TableOfContentsModel< + IEditorHeading, + IDocumentWidget +> { + /** + * 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="..."]` + */ + get documentType(): string { + return 'python'; + } + + /** + * Produce the headings for a document. + * + * @returns The list of new headings or `null` if nothing needs to be updated. + */ + protected async getHeadings(): Promise { + if (!this.isActive) { + return Promise.resolve(null); + } + + // Split the text into lines: + const lines = this.widget.content.model.value.text.split( + '\n' + ) as Array; + + // Iterate over the lines to get the heading level and text for each line: + let headings = new Array(); + let processingImports = false; + + let indent = 1; + + let lineIdx = -1; + for (const line of lines) { + lineIdx++; + let hasKeyword: RegExpExecArray | null; + if (KEYWORDS.flags.includes('d')) { + hasKeyword = KEYWORDS.exec(line); + } else { + const { default: execWithIndices } = await import( + 'regexp-match-indices' + ); + hasKeyword = execWithIndices(KEYWORDS, line); + } + if (hasKeyword) { + // Index 0 contains the spaces, index 1 is the keyword group + const [start] = (hasKeyword as any).indices[1]; + if (indent === 1 && start > 0) { + indent = start; + } + + const isImport = ['from ', 'import '].includes(hasKeyword[1]); + if (isImport && processingImports) { + continue; + } + processingImports = isImport; + + const level = 1 + start / indent; + + if (level > this.configuration.maximalDepth) { + continue; + } + + headings.push({ + text: line.slice(start), + level, + line: lineIdx + }); + } + } + + return Promise.resolve(headings); + } +} + +/** + * Table of content model factory for Python files. + */ +export class PythonTableOfContentsFactory extends EditorTableOfContentsFactory { + /** + * Whether the factory can handle the widget or not. + * + * @param widget - widget + * @returns boolean indicating a ToC can be generated + */ + isApplicable(widget: Widget): boolean { + const isApplicable = super.isApplicable(widget); + + if (isApplicable) { + let mime = (widget as any).content?.model?.mimeType; + return ( + mime && + (mime === 'application/x-python-code' || mime === 'text/x-python') + ); + } + return false; + } + + /** + * 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 + */ + protected _createNew( + widget: IDocumentWidget, + configuration?: TableOfContents.IConfig + ): PythonTableOfContentsModel { + return new PythonTableOfContentsModel(widget, configuration); + } +} diff --git a/packages/fileeditor/src/tokens.ts b/packages/fileeditor/src/tokens.ts index 68e58f5..8bb925b 100644 --- a/packages/fileeditor/src/tokens.ts +++ b/packages/fileeditor/src/tokens.ts @@ -12,11 +12,9 @@ import { FileEditor } from './widget'; export interface IEditorTracker extends IWidgetTracker> {} -/* tslint:disable */ /** * The editor tracker token. */ export const IEditorTracker = new Token( '@jupyterlab/fileeditor:IEditorTracker' ); -/* tslint:enable */ diff --git a/packages/fileeditor/src/widget.ts b/packages/fileeditor/src/widget.ts index c802226..fd9a8a7 100644 --- a/packages/fileeditor/src/widget.ts +++ b/packages/fileeditor/src/widget.ts @@ -28,128 +28,6 @@ const CODE_RUNNER = 'jpCodeRunner'; */ const UNDOER = 'jpUndoer'; -/** - * A code editor wrapper for the file editor. - */ -export class FileEditorCodeWrapper extends CodeEditorWrapper { - /** - * Construct a new editor widget. - */ - constructor(options: FileEditor.IOptions) { - super({ - factory: options.factory, - model: options.context.model - }); - - const context = (this._context = options.context); - const editor = this.editor; - - this.addClass('jp-FileEditorCodeWrapper'); - this.node.dataset[CODE_RUNNER] = 'true'; - this.node.dataset[UNDOER] = 'true'; - - editor.model.value.text = context.model.toString(); - void context.ready.then(() => { - this._onContextReady(); - }); - - if (context.model.modelDB.isCollaborative) { - const modelDB = context.model.modelDB; - void modelDB.connected.then(() => { - const collaborators = modelDB.collaborators; - if (!collaborators) { - return; - } - - // Setup the selection style for collaborators - const localCollaborator = collaborators.localCollaborator; - this.editor.uuid = localCollaborator.sessionId; - - this.editor.selectionStyle = { - ...CodeEditor.defaultSelectionStyle, - color: localCollaborator.color - }; - - collaborators.changed.connect(this._onCollaboratorsChanged, this); - // Trigger an initial onCollaboratorsChanged event. - this._onCollaboratorsChanged(); - }); - } - } - - /** - * Get the context for the editor widget. - */ - get context(): DocumentRegistry.Context { - return this._context; - } - - /** - * A promise that resolves when the file editor is ready. - */ - get ready(): Promise { - return this._ready.promise; - } - - /** - * Handle actions that should be taken when the context is ready. - */ - private _onContextReady(): void { - if (this.isDisposed) { - return; - } - const contextModel = this._context.model; - const editor = this.editor; - const editorModel = editor.model; - - // Set the editor model value. - editorModel.value.text = contextModel.toString(); - - // Prevent the initial loading from disk from being in the editor history. - editor.clearHistory(); - - // Wire signal connections. - contextModel.contentChanged.connect(this._onContentChanged, this); - - // Resolve the ready promise. - this._ready.resolve(undefined); - } - - /** - * Handle a change in context model content. - */ - private _onContentChanged(): void { - const editorModel = this.editor.model; - const oldValue = editorModel.value.text; - const newValue = this._context.model.toString(); - - if (oldValue !== newValue) { - editorModel.value.text = newValue; - } - } - - /** - * Handle a change to the collaborators on the model - * by updating UI elements associated with them. - */ - private _onCollaboratorsChanged(): void { - // If there are selections corresponding to non-collaborators, - // they are stale and should be removed. - const collaborators = this._context.model.modelDB.collaborators; - if (!collaborators) { - return; - } - for (const key of this.editor.model.selections.keys()) { - if (!collaborators.has(key)) { - this.editor.model.selections.delete(key); - } - } - } - - protected _context: DocumentRegistry.Context; - private _ready = new PromiseDelegate(); -} - /** * A widget for editors. */ @@ -164,12 +42,21 @@ export class FileEditor extends Widget { const context = (this._context = options.context); this._mimeTypeService = options.mimeTypeService; - const editorWidget = (this.editorWidget = new FileEditorCodeWrapper( - options - )); + const editorWidget = (this._editorWidget = new CodeEditorWrapper({ + factory: options.factory, + model: context.model + })); + this._editorWidget.addClass('jp-FileEditorCodeWrapper'); + this._editorWidget.node.dataset[CODE_RUNNER] = 'true'; + this._editorWidget.node.dataset[UNDOER] = 'true'; + this.editor = editorWidget.editor; this.model = editorWidget.model; + void context.ready.then(() => { + this._onContextReady(); + }); + // Listen for changes to the path. context.pathChanged.connect(this._onPathChanged, this); this._onPathChanged(); @@ -182,14 +69,14 @@ export class FileEditor extends Widget { * Get the context for the editor widget. */ get context(): DocumentRegistry.Context { - return this.editorWidget.context; + return this._context; } /** * A promise that resolves when the file editor is ready. */ get ready(): Promise { - return this.editorWidget.ready; + return this.ready; } /** @@ -248,6 +135,20 @@ export class FileEditor extends Widget { } } + /** + * Handle actions that should be taken when the context is ready. + */ + private _onContextReady(): void { + if (this.isDisposed) { + return; + } + + // Prevent the initial loading from disk from being in the editor history. + this.editor.clearHistory(); + // Resolve the ready promise. + this._ready.resolve(undefined); + } + /** * Handle a change to the path. */ @@ -255,16 +156,16 @@ export class FileEditor extends Widget { const editor = this.editor; const localPath = this._context.localPath; - editor.model.mimeType = this._mimeTypeService.getMimeTypeByFilePath( - localPath - ); + editor.model.mimeType = + this._mimeTypeService.getMimeTypeByFilePath(localPath); } - private editorWidget: FileEditorCodeWrapper; - public model: CodeEditor.IModel; - public editor: CodeEditor.IEditor; - protected _context: DocumentRegistry.Context; + model: CodeEditor.IModel; + editor: CodeEditor.IEditor; + private _context: DocumentRegistry.Context; + private _editorWidget: CodeEditorWrapper; private _mimeTypeService: IEditorMimeTypeService; + private _ready = new PromiseDelegate(); } /** diff --git a/packages/fileeditor/style/base.css b/packages/fileeditor/style/base.css index 0534fc1..4f98fce 100644 --- a/packages/fileeditor/style/base.css +++ b/packages/fileeditor/style/base.css @@ -3,9 +3,6 @@ | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------*/ -.jp-FileEditor { -} - /*----------------------------------------------------------------------------- | Presentation Mode (.jp-mod-presentationMode) |----------------------------------------------------------------------------*/ @@ -13,3 +10,11 @@ .jp-mod-presentationMode .jp-FileEditor { --jp-code-font-size: var(--jp-code-presentation-font-size); } + +.jp-FileEditorCodeWrapper { + overflow: auto; +} + +.jp-FileEditorCodeWrapper .cm-editor { + height: 100%; +} diff --git a/packages/fileeditor/style/index.css b/packages/fileeditor/style/index.css index 478404a..2b36a20 100644 --- a/packages/fileeditor/style/index.css +++ b/packages/fileeditor/style/index.css @@ -8,6 +8,10 @@ @import url('https://github.com/~@jupyterlab/ui-components/style/index.css'); @import url('https://github.com/~@jupyterlab/apputils/style/index.css'); @import url('https://github.com/~@jupyterlab/codeeditor/style/index.css'); +@import url('https://github.com/~@jupyterlab/documentsearch/style/index.css'); +@import url('https://github.com/~@jupyterlab/codemirror/style/index.css'); @import url('https://github.com/~@jupyterlab/docregistry/style/index.css'); +@import url('https://github.com/~@jupyterlab/lsp/style/index.css'); +@import url('https://github.com/~@jupyterlab/toc/style/index.css'); @import url('https://github.com/base.css'); diff --git a/packages/fileeditor/style/index.js b/packages/fileeditor/style/index.js index c9ba960..eccbe09 100644 --- a/packages/fileeditor/style/index.js +++ b/packages/fileeditor/style/index.js @@ -8,6 +8,10 @@ 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 '@jupyterlab/documentsearch/style/index.js'; +import '@jupyterlab/codemirror/style/index.js'; import '@jupyterlab/docregistry/style/index.js'; +import '@jupyterlab/lsp/style/index.js'; +import '@jupyterlab/toc/style/index.js'; import './base.css'; diff --git a/packages/fileeditor/test/python.spec.ts b/packages/fileeditor/test/python.spec.ts new file mode 100644 index 0000000..5c697d5 --- /dev/null +++ b/packages/fileeditor/test/python.spec.ts @@ -0,0 +1,153 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { + IEditorHeading, + PythonTableOfContentsModel +} from '@jupyterlab/fileeditor'; +import { signalToPromise } from '@jupyterlab/testutils'; + +describe('@jupyterlab/fileeditor', () => { + describe('PythonTableOfContentsModel', () => { + describe('#getHeadings', () => { + it.each<[string, IEditorHeading[]]>([ + ['', []], + ['a = 2', []], + [ + 'def f(a, b):', + [ + { + text: 'def f(a, b):', + level: 1, + line: 0 + } + ] + ], + [ + 'class Klass:', + [ + { + text: 'class Klass:', + level: 1, + line: 0 + } + ] + ], + [ + 'import pathlib', + [ + { + text: 'import pathlib', + level: 1, + line: 0 + } + ] + ], + [ + 'from pathlib import Path', + [ + { + text: 'from pathlib import Path', + level: 1, + line: 0 + } + ] + ], + [ + 'import subprocess\nfrom pathlib import Path\n\nimport tempfile', + [ + { + text: 'import subprocess', + level: 1, + line: 0 + } + ] + ], + [ + 'def f(a, b):\n def g():\n pass', + [ + { + text: 'def f(a, b):', + level: 1, + line: 0 + }, + { + text: 'def g():', + level: 2, + line: 1 + } + ] + ], + [ + 'def f(a, b):\n def g():\n class C:', + [ + { + text: 'def f(a, b):', + level: 1, + line: 0 + }, + { + text: 'def g():', + level: 2, + line: 1 + }, + { + text: 'class C:', + level: 3, + line: 2 + } + ] + ], + [ + 'def f(a, b):\n def g():\n pass\n pass\ndef h():', + [ + { + text: 'def f(a, b):', + level: 1, + line: 0 + }, + { + text: 'def g():', + level: 2, + line: 1 + }, + { + text: 'def h():', + level: 1, + line: 4 + } + ] + ] + ])('should extract headings from %s', async (text, headers) => { + const model = new PythonTableOfContentsModel({ + content: { + model: { + mimeType: 'text/x-python', + value: { + text + } as any + } as any + } as any + } as any); + + const newHeadings = signalToPromise(model.headingsChanged); + model.isActive = true; // This will trigger refresh + if (headers.length > 0) { + // If text has no associated headings the new computed headings + // are gonna be empty. So the signal won't be emitted. + await newHeadings; + } else { + await model.refresh(); + } + const headings = model.headings; + + expect(headings).toHaveLength(headers.length); + for (let i = 0; i < headers.length; i++) { + expect(headings[i]).toEqual(headers[i]); + } + }); + }); + }); +}); diff --git a/packages/fileeditor/test/widget.spec.ts b/packages/fileeditor/test/widget.spec.ts index c2a51a3..d9d0af4 100644 --- a/packages/fileeditor/test/widget.spec.ts +++ b/packages/fileeditor/test/widget.spec.ts @@ -11,11 +11,7 @@ import { DocumentWidget, TextModelFactory } from '@jupyterlab/docregistry'; -import { - FileEditor, - FileEditorCodeWrapper, - FileEditorFactory -} from '@jupyterlab/fileeditor'; +import { FileEditor, FileEditorFactory } from '@jupyterlab/fileeditor'; import { ServiceManager } from '@jupyterlab/services'; import { framePromise } from '@jupyterlab/testutils'; import * as Mock from '@jupyterlab/testutils/lib/mock'; @@ -62,43 +58,6 @@ describe('fileeditorcodewrapper', () => { return manager.ready; }); - describe('FileEditorCodeWrapper', () => { - let widget: FileEditorCodeWrapper; - - beforeEach(() => { - const path = UUID.uuid4() + '.py'; - context = new Context({ manager, factory: modelFactory, path }); - widget = new FileEditorCodeWrapper({ - factory: options => factoryService.newDocumentEditor(options), - mimeTypeService, - context - }); - }); - - afterEach(() => { - widget.dispose(); - }); - - describe('#constructor()', () => { - it('should create an editor wrapper widget', () => { - expect(widget).toBeInstanceOf(FileEditorCodeWrapper); - }); - - it('should update the editor text when the model changes', async () => { - await context.initialize(true); - await context.ready; - widget.context.model.fromString('foo'); - expect(widget.editor.model.value.text).toBe('foo'); - }); - }); - - describe('#context', () => { - it('should be the context used by the widget', () => { - expect(widget.context).toBe(context); - }); - }); - }); - describe('FileEditor', () => { let widget: LogFileEditor; diff --git a/packages/fileeditor/tsconfig.json b/packages/fileeditor/tsconfig.json index decd92c..c1f4559 100644 --- a/packages/fileeditor/tsconfig.json +++ b/packages/fileeditor/tsconfig.json @@ -4,7 +4,7 @@ "outDir": "lib", "rootDir": "src" }, - "include": ["src/*"], + "include": ["src/**/*"], "references": [ { "path": "../apputils" @@ -12,12 +12,24 @@ { "path": "../codeeditor" }, + { + "path": "../codemirror" + }, { "path": "../docregistry" }, + { + "path": "../documentsearch" + }, + { + "path": "../lsp" + }, { "path": "../statusbar" }, + { + "path": "../toc" + }, { "path": "../translation" }, diff --git a/packages/fileeditor/tsconfig.test.json b/packages/fileeditor/tsconfig.test.json index 26d0ca5..fe5520f 100644 --- a/packages/fileeditor/tsconfig.test.json +++ b/packages/fileeditor/tsconfig.test.json @@ -9,40 +9,34 @@ "path": "../codeeditor" }, { - "path": "../docregistry" - }, - { - "path": "../statusbar" + "path": "../codemirror" }, { - "path": "../translation" - }, - { - "path": "../ui-components" + "path": "../docregistry" }, { - "path": "." + "path": "../documentsearch" }, { - "path": "../../testutils" + "path": "../lsp" }, { - "path": "../apputils" + "path": "../statusbar" }, { - "path": "../codeeditor" + "path": "../toc" }, { - "path": "../docregistry" + "path": "../translation" }, { - "path": "../statusbar" + "path": "../ui-components" }, { - "path": "../translation" + "path": "." }, { - "path": "../ui-components" + "path": "../../testutils" } ] } diff --git a/packages/help-extension/package.json b/packages/help-extension/package.json index d234172..991a191 100644 --- a/packages/help-extension/package.json +++ b/packages/help-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/help-extension", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Help Extension", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -37,23 +37,24 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/application": "^3.3.2", - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/mainmenu": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@jupyterlab/translation": "^3.3.2", - "@jupyterlab/ui-components": "^3.3.2", - "@lumino/coreutils": "^1.5.3", - "@lumino/signaling": "^1.4.3", - "@lumino/virtualdom": "^1.8.0", - "@lumino/widgets": "^1.19.0", + "@jupyterlab/application": "^4.0.0-alpha.12", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/mainmenu": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@jupyterlab/translation": "^4.0.0-alpha.12", + "@jupyterlab/ui-components": "^4.0.0-alpha.27", + "@lumino/algorithm": "^1.9.1", + "@lumino/coreutils": "^1.12.0", + "@lumino/signaling": "^1.10.1", + "@lumino/virtualdom": "^1.14.1", + "@lumino/widgets": "^1.33.0", "react": "^17.0.1" }, "devDependencies": { "rimraf": "~3.0.0", - "typedoc": "~0.21.2", - "typescript": "~4.1.3" + "typedoc": "~0.22.10", + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/packages/help-extension/schema/launch-classic.json b/packages/help-extension/schema/launch-classic.json index 7a369b6..5765281 100644 --- a/packages/help-extension/schema/launch-classic.json +++ b/packages/help-extension/schema/launch-classic.json @@ -8,10 +8,6 @@ "type": "separator", "rank": 1 }, - { - "command": "help:launch-classic-notebook", - "rank": 1 - }, { "type": "separator", "rank": 1 diff --git a/packages/help-extension/src/index.tsx b/packages/help-extension/src/index.tsx index c0e9db5..0696afd 100644 --- a/packages/help-extension/src/index.tsx +++ b/packages/help-extension/src/index.tsx @@ -6,21 +6,36 @@ */ import { + ILabShell, + ILayoutRestorer, JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; import { Dialog, ICommandPalette, - showDialog + MainAreaWidget, + showDialog, + WidgetTracker } from '@jupyterlab/apputils'; -import { PageConfig } from '@jupyterlab/coreutils'; +import { PageConfig, URLExt } from '@jupyterlab/coreutils'; +import { IMainMenu } from '@jupyterlab/mainmenu'; +import { Kernel, KernelMessage, Session } from '@jupyterlab/services'; import { ITranslator } from '@jupyterlab/translation'; import { + CommandToolbarButton, + copyrightIcon, + IFrame, jupyterIcon, - jupyterlabWordmarkIcon + jupyterlabWordmarkIcon, + refreshIcon, + Toolbar } from '@jupyterlab/ui-components'; +import { ReadonlyJSONObject } from '@lumino/coreutils'; +import { each } from '@lumino/algorithm'; +import { Menu } from '@lumino/widgets'; import * as React from 'react'; +import { Licenses } from './licenses'; /** * The command IDs used by the help plugin. @@ -38,8 +53,6 @@ namespace CommandIDs { export const hide = 'help:hide'; - export const launchClassic = 'help:launch-classic-notebook'; - export const jupyterForum = 'help:jupyter-forum'; export const licenses = 'help:licenses'; @@ -49,6 +62,16 @@ namespace CommandIDs { export const refreshLicenses = 'help:licenses-refresh'; } +/** + * A flag denoting whether the application is loaded over HTTPS. + */ +const LAB_IS_SECURE = window.location.protocol === 'https:'; + +/** + * The class name added to the help widget. + */ +const HELP_CLASS = 'jp-Help'; + /** * Add a command to show an About dialog. */ @@ -67,7 +90,7 @@ const about: JupyterFrontEndPlugin = { const category = trans.__('Help'); commands.addCommand(CommandIDs.about, { - label: trans.__('About %1', 'ElixirNote'), + label: trans.__('About %1', app.name), execute: () => { // Create the header of the about dialog const versionNumber = trans.__('Version %1', app.version); @@ -87,9 +110,9 @@ const about: JupyterFrontEndPlugin = { ); // Create the body of the about dialog - const jupyterURL = 'https://github.com/ElixirNote'; + const jupyterURL = 'https://jupyter.org/about.html'; const contributorsURL = - 'https://github.com/ElixirNote'; + 'https://github.com/jupyterlab/jupyterlab/graphs/contributors'; const externalLinks = (
    = { rel="noopener noreferrer" className="jp-Button-flat" > - {trans.__('ABOUT PROJECT ELIXIRNOTE')} + {trans.__('ABOUT PROJECT JUPYTER')} ); const copyright = ( - {trans.__('© 2022 Project ElixirNote Contributors')} + {trans.__('© 2015-2022 Project Jupyter Contributors')} ); const body = ( @@ -142,10 +165,10 @@ const about: JupyterFrontEndPlugin = { }; /** - * A plugin to add a command to open the Classic Notebook interface. + * A plugin to add a command to open the Jupyter Forum. */ -const launchClassic: JupyterFrontEndPlugin = { - id: '@jupyterlab/help-extension:launch-classic', +const jupyterForum: JupyterFrontEndPlugin = { + id: '@jupyterlab/help-extension:jupyter-forum', autoStart: true, requires: [ITranslator], optional: [ICommandPalette], @@ -158,53 +181,452 @@ const launchClassic: JupyterFrontEndPlugin = { const trans = translator.load('jupyterlab'); const category = trans.__('Help'); - commands.addCommand(CommandIDs.launchClassic, { - label: trans.__('Launch Classic Notebook'), + commands.addCommand(CommandIDs.jupyterForum, { + label: trans.__('Jupyter Forum'), execute: () => { - window.open(PageConfig.getBaseUrl() + 'tree'); + window.open('https://discourse.jupyter.org/c/jupyterlab'); } }); if (palette) { - palette.addItem({ command: CommandIDs.launchClassic, category }); + palette.addItem({ command: CommandIDs.jupyterForum, category }); } } }; /** - * A plugin to add a command to open the Jupyter Forum. + * A plugin to add a list of resources to the help menu. */ -const jupyterForum: JupyterFrontEndPlugin = { - id: '@jupyterlab/help-extension:jupyter-forum', +const resources: JupyterFrontEndPlugin = { + id: '@jupyterlab/help-extension:resources', autoStart: true, - requires: [ITranslator], - optional: [ICommandPalette], + requires: [IMainMenu, ITranslator], + optional: [ILabShell, ICommandPalette, ILayoutRestorer], activate: ( app: JupyterFrontEnd, + mainMenu: IMainMenu, translator: ITranslator, - palette: ICommandPalette | null + labShell: ILabShell | null, + palette: ICommandPalette | null, + restorer: ILayoutRestorer | null ): void => { - const { commands } = app; const trans = translator.load('jupyterlab'); + let counter = 0; const category = trans.__('Help'); + const namespace = 'help-doc'; + const { commands, shell, serviceManager } = app; + const tracker = new WidgetTracker>({ namespace }); + const resources = [ + { + text: trans.__('JupyterLab Reference'), + url: 'https://jupyterlab.readthedocs.io/en/latest/' + }, + { + text: trans.__('JupyterLab FAQ'), + url: 'https://jupyterlab.readthedocs.io/en/latest/getting_started/faq.html' + }, + { + text: trans.__('Jupyter Reference'), + url: 'https://jupyter.org/documentation' + }, + { + text: trans.__('Markdown Reference'), + url: 'https://commonmark.org/help/' + } + ]; - commands.addCommand(CommandIDs.jupyterForum, { - label: trans.__('ElixirNote Handbook'), - execute: () => { - window.open(''); + resources.sort((a: any, b: any) => { + return a.text.localeCompare(b.text); + }); + + /** + * Create a new HelpWidget widget. + */ + function newHelpWidget(url: string, text: string): MainAreaWidget diff --git a/server/docs/source/developers/contents.rst b/server/docs/source/developers/contents.rst deleted file mode 100644 index 28d2a33..0000000 --- a/server/docs/source/developers/contents.rst +++ /dev/null @@ -1,289 +0,0 @@ -.. _contents_api: - -Contents API -============ - -.. currentmodule:: jupyter_server.services.contents - -The Jupyter Notebook web application provides a graphical interface for -creating, opening, renaming, and deleting files in a virtual filesystem. - -The :class:`~manager.ContentsManager` class defines an abstract -API for translating these interactions into operations on a particular storage -medium. The default implementation, -:class:`~filemanager.FileContentsManager`, uses the local -filesystem of the server for storage and straightforwardly serializes notebooks -into JSON. Users can override these behaviors by supplying custom subclasses -of ContentsManager. - -This section describes the interface implemented by ContentsManager subclasses. -We refer to this interface as the **Contents API**. - -Data Model ----------- - -.. currentmodule:: jupyter_server.services.contents.manager - -Filesystem Entities -~~~~~~~~~~~~~~~~~~~ -.. _notebook models: - -ContentsManager methods represent virtual filesystem entities as dictionaries, -which we refer to as **models**. - -Models may contain the following entries: - -+--------------------+-----------+------------------------------+ -| Key | Type |Info | -+====================+===========+==============================+ -|**name** |unicode |Basename of the entity. | -+--------------------+-----------+------------------------------+ -|**path** |unicode |Full | -| | |(:ref:`API-style`) | -| | |path to the entity. | -+--------------------+-----------+------------------------------+ -|**type** |unicode |The entity type. One of | -| | |``"notebook"``, ``"file"`` or | -| | |``"directory"``. | -+--------------------+-----------+------------------------------+ -|**created** |datetime |Creation date of the entity. | -+--------------------+-----------+------------------------------+ -|**last_modified** |datetime |Last modified date of the | -| | |entity. | -+--------------------+-----------+------------------------------+ -|**content** |variable |The "content" of the entity. | -| | |(:ref:`See | -| | |Below`) | -+--------------------+-----------+------------------------------+ -|**mimetype** |unicode or |The mimetype of ``content``, | -| |``None`` |if any. (:ref:`See | -| | |Below`) | -+--------------------+-----------+------------------------------+ -|**format** |unicode or |The format of ``content``, | -| |``None`` |if any. (:ref:`See | -| | |Below`) | -+--------------------+-----------+------------------------------+ - -.. _modelcontent: - -Certain model fields vary in structure depending on the ``type`` field of the -model. There are three model types: **notebook**, **file**, and **directory**. - -- ``notebook`` models - - The ``format`` field is always ``"json"``. - - The ``mimetype`` field is always ``None``. - - The ``content`` field contains a - :class:`nbformat.notebooknode.NotebookNode` representing the .ipynb file - represented by the model. See the `NBFormat`_ documentation for a full - description. - -- ``file`` models - - The ``format`` field is either ``"text"`` or ``"base64"``. - - The ``mimetype`` field is ``text/plain`` for text-format models and - ``application/octet-stream`` for base64-format models. - - The ``content`` field is always of type ``unicode``. For text-format - file models, ``content`` simply contains the file's bytes after decoding - as UTF-8. Non-text (``base64``) files are read as bytes, base64 encoded, - and then decoded as UTF-8. - -- ``directory`` models - - The ``format`` field is always ``"json"``. - - The ``mimetype`` field is always ``None``. - - The ``content`` field contains a list of :ref:`content-free` - models representing the entities in the directory. - -.. note:: - - .. _contentfree: - - In certain circumstances, we don't need the full content of an entity to - complete a Contents API request. In such cases, we omit the ``mimetype``, - ``content``, and ``format`` keys from the model. This most commonly occurs - when listing a directory, in which circumstance we represent files within - the directory as content-less models to avoid having to recursively traverse - and serialize the entire filesystem. - -**Sample Models** - -.. code-block:: python - - # Notebook Model with Content - { - 'content': { - 'metadata': {}, - 'nbformat': 4, - 'nbformat_minor': 0, - 'cells': [ - { - 'cell_type': 'markdown', - 'metadata': {}, - 'source': 'Some **Markdown**', - }, - ], - }, - 'created': datetime(2015, 7, 25, 19, 50, 19, 19865), - 'format': 'json', - 'last_modified': datetime(2015, 7, 25, 19, 50, 19, 19865), - 'mimetype': None, - 'name': 'a.ipynb', - 'path': 'foo/a.ipynb', - 'type': 'notebook', - 'writable': True, - } - - # Notebook Model without Content - { - 'content': None, - 'created': datetime.datetime(2015, 7, 25, 20, 17, 33, 271931), - 'format': None, - 'last_modified': datetime.datetime(2015, 7, 25, 20, 17, 33, 271931), - 'mimetype': None, - 'name': 'a.ipynb', - 'path': 'foo/a.ipynb', - 'type': 'notebook', - 'writable': True - } - - -API Paths -~~~~~~~~~ -.. _apipaths: - -ContentsManager methods represent the locations of filesystem resources as -**API-style paths**. Such paths are interpreted as relative to the root -directory of the notebook server. For compatibility across systems, the -following guarantees are made: - -* Paths are always ``unicode``, not ``bytes``. -* Paths are not URL-escaped. -* Paths are always forward-slash (/) delimited, even on Windows. -* Leading and trailing slashes are stripped. For example, ``/foo/bar/buzz/`` - becomes ``foo/bar/buzz``. -* The empty string (``""``) represents the root directory. - - -Writing a Custom ContentsManager --------------------------------- - -The default ContentsManager is designed for users running the notebook as an -application on a personal computer. It stores notebooks as .ipynb files on the -local filesystem, and it maps files and directories in the Notebook UI to files -and directories on disk. It is possible to override how notebooks are stored -by implementing your own custom subclass of ``ContentsManager``. For example, -if you deploy the notebook in a context where you don't trust or don't have -access to the filesystem of the notebook server, it's possible to write your -own ContentsManager that stores notebooks and files in a database. - - -Required Methods -~~~~~~~~~~~~~~~~ - -A minimal complete implementation of a custom -:class:`~manager.ContentsManager` must implement the following -methods: - -.. autosummary:: - ContentsManager.get - ContentsManager.save - ContentsManager.delete_file - ContentsManager.rename_file - ContentsManager.file_exists - ContentsManager.dir_exists - ContentsManager.is_hidden - -You may be required to specify a Checkpoints object, as the default one, -``FileCheckpoints``, could be incompatible with your custom -ContentsManager. - -Customizing Checkpoints ------------------------ -.. currentmodule:: jupyter_server.services.contents.checkpoints - -Customized Checkpoint definitions allows behavior to be -altered and extended. - -The ``Checkpoints`` and ``GenericCheckpointsMixin`` classes -(from :mod:`jupyter_server.services.contents.checkpoints`) -have reusable code and are intended to be used together, -but require the following methods to be implemented. - -.. autosummary:: - Checkpoints.rename_checkpoint - Checkpoints.list_checkpoints - Checkpoints.delete_checkpoint - GenericCheckpointsMixin.create_file_checkpoint - GenericCheckpointsMixin.create_notebook_checkpoint - GenericCheckpointsMixin.get_file_checkpoint - GenericCheckpointsMixin.get_notebook_checkpoint - -No-op example -~~~~~~~~~~~~~ - -Here is an example of a no-op checkpoints object - note the mixin -comes first. The docstrings indicate what each method should do or -return for a more complete implementation. - -.. code-block:: python - - class NoOpCheckpoints(GenericCheckpointsMixin, Checkpoints): - """requires the following methods:""" - def create_file_checkpoint(self, content, format, path): - """ -> checkpoint model""" - def create_notebook_checkpoint(self, nb, path): - """ -> checkpoint model""" - def get_file_checkpoint(self, checkpoint_id, path): - """ -> {'type': 'file', 'content': , 'format': {'text', 'base64'}}""" - def get_notebook_checkpoint(self, checkpoint_id, path): - """ -> {'type': 'notebook', 'content': }""" - def delete_checkpoint(self, checkpoint_id, path): - """deletes a checkpoint for a file""" - def list_checkpoints(self, path): - """returns a list of checkpoint models for a given file, - default just does one per file - """ - return [] - def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """renames checkpoint from old path to new path""" - -See ``GenericFileCheckpoints`` in :mod:`notebook.services.contents.filecheckpoints` -for a more complete example. - -Testing -------- -.. currentmodule:: jupyter_server.services.contents.tests - -:mod:`jupyter_server.services.contents.tests` includes several test suites written -against the abstract Contents API. This means that an excellent way to test a -new ContentsManager subclass is to subclass our tests to make them use your -ContentsManager. - -.. note:: - - PGContents_ is an example of a complete implementation of a custom - ``ContentsManager``. It stores notebooks and files in PostgreSQL_ and encodes - directories as SQL relations. PGContents also provides an example of how to - re-use the notebook's tests. - -.. _NBFormat: https://nbformat.readthedocs.io/en/latest/index.html -.. _PGContents: https://github.com/quantopian/pgcontents -.. _PostgreSQL: https://www.postgresql.org/ - -Asynchronous Support --------------------- - -An asynchronous version of the Contents API is available to run slow IO processes concurrently. - -- :class:`~manager.AsyncContentsManager` -- :class:`~filemanager.AsyncFileContentsManager` -- :class:`~largefilemanager.AsyncLargeFileManager` -- :class:`~checkpoints.AsyncCheckpoints` -- :class:`~checkpoints.AsyncGenericCheckpointsMixin` - -.. note:: - - .. _asynccontents: - - In most cases, the non-asynchronous Contents API is performant for local filesystems. - However, if the Jupyter Notebook web application is interacting with a high-latent virtual filesystem, you may see performance gains by using the asynchronous version. - For example, if you're experiencing terminal lag in the web application due to the slow and blocking file operations, the asynchronous version can reduce the lag. - Before opting in, comparing both non-async and async options' performances is recommended. diff --git a/server/docs/source/developers/dependency.rst b/server/docs/source/developers/dependency.rst deleted file mode 100644 index feaf90b..0000000 --- a/server/docs/source/developers/dependency.rst +++ /dev/null @@ -1,19 +0,0 @@ -Depending on Jupyter Server -=========================== - -If your project depends directly on Jupyter Server, be sure to watch Jupyter Server's ChangeLog and pin your project to a version that works for your application. Major releases represent possible backwards-compatibility breaking API changes or features. - -When a new major version in released on PyPI, a branch for that version will be created in this repository, and the version of the master branch will be bumped to the next major version number. That way, the master branch always reflects the latest un-released version. - -To install the latest patch of a given version: - -.. code-block:: console - - > pip install jupyter_server --upgrade - - -To pin your jupyter_server install to a specific version: - -.. code-block:: console - - > pip install jupyter_server==1.0.0 diff --git a/server/docs/source/developers/extensions.rst b/server/docs/source/developers/extensions.rst deleted file mode 100644 index 378f135..0000000 --- a/server/docs/source/developers/extensions.rst +++ /dev/null @@ -1,553 +0,0 @@ -================= -Server Extensions -================= - -A Jupyter Server extension is typically a module or package that extends to Server’s REST API/endpoints—i.e. adds extra request handlers to Server’s Tornado Web Application. - -You can check some simple examples on the `examples folder -`_ in the GitHub jupyter_server repository. - -Authoring a basic server extension -================================== - -The simplest way to write a Jupyter Server extension is to write an extension module with a ``_load_jupyter_server_extension`` function. This function should take a single argument, an instance of the ``ServerApp``. - - -.. code-block:: python - - def _load_jupyter_server_extension(serverapp: jupyter_server.serverapp.ServerApp): - """ - This function is called when the extension is loaded. - """ - pass - - -Adding extension endpoints --------------------------- - -The easiest way to add endpoints and handle incoming requests is to subclass the ``JupyterHandler`` (which itself is a subclass of Tornado's ``RequestHandler``). - -.. code-block:: python - - from jupyter_server.base.handlers import JupyterHandler - import tornado - - class MyExtensionHandler(JupyterHandler): - - @tornado.web.authenticated - def get(self): - ... - - @tornado.web.authenticated - def post(self): - ... - -.. note:: - It is best practice to wrap each handler method with the ``authenticated`` decorator to ensure that each request is authenticated by the server. - -Then add this handler to Jupyter Server's Web Application through the ``_load_jupyter_server_extension`` function. - -.. code-block:: python - - def _load_jupyter_server_extension(serverapp: jupyter_server.serverapp.ServerApp): - """ - This function is called when the extension is loaded. - """ - handlers = [ - ('/myextension/hello', MyExtensionHandler) - ] - serverapp.web_app.add_handlers('.*$', handlers) - - -Making an extension discoverable --------------------------------- - -To make this extension discoverable to Jupyter Server, first define a ``_jupyter_server_extension_points()`` function at the root of the module/package. This function returns metadata describing how to load the extension. Usually, this requires a ``module`` key with the import path to the extension's ``_load_jupyter_server_extension`` function. - -.. code-block:: python - - def _jupyter_server_extension_points(): - """ - Returns a list of dictionaries with metadata describing - where to find the `_load_jupyter_server_extension` function. - """ - return [ - { - "module": "my_extension" - } - ] - -Second, add the extension to the ServerApp's ``jpserver_extensions`` trait. This can be manually added by users in their ``jupyter_server_config.py`` file, - -.. code-block:: python - - c.ServerApp.jpserver_extensions = { - "my_extension": True - } - -or loaded from a JSON file in the ``jupyter_server_config.d`` directory under one of `Jupyter's paths`_. (See the `Distributing a server extension`_ section for details on how to automatically enabled your extension when users install it.) - -.. code-block:: python - - { - "ServerApp": { - "jpserver_extensions": { - "my_extension": true - } - } - } - - -Authoring a configurable extension application -============================================== - -Some extensions are full-fledged client applications that sit on top of the Jupyter Server. For example, `JupyterLab `_ is a server extension. It can be launched from the command line, configured by CLI or config files, and serves+loads static assets behind the server (i.e. html templates, Javascript, etc.) - -Jupyter Server offers a convenient base class, ``ExtensionsApp``, that handles most of the boilerplate code for building such extensions. - -Anatomy of an ``ExtensionApp`` ------------------------------- - -An ExtensionApp: - - - has traits. - - is configurable (from file or CLI) - - has a name (see the ``name`` trait). - - has an entrypoint, ``jupyter ``. - - can serve static content from the ``/static//`` endpoint. - - can add new endpoints to the Jupyter Server. - -The basic structure of an ExtensionApp is shown below: - -.. code-block:: python - - from jupyter_server.extension.application import ExtensionApp - - - class MyExtensionApp(ExtensionApp): - - # -------------- Required traits -------------- - name = "myextension" - default_url = "/myextension" - load_other_extensions = True - file_url_prefix = "/render" - - # --- ExtensionApp traits you can configure --- - static_paths = [...] - template_paths = [...] - settings = {...} - handlers = [...] - - # ----------- add custom traits below --------- - ... - - def initialize_settings(self): - ... - # Update the self.settings trait to pass extra - # settings to the underlying Tornado Web Application. - self.settings.update({'':...}) - - def initialize_handlers(self): - ... - # Extend the self.handlers trait - self.handlers.extend(...) - - def initialize_templates(self): - ... - # Change the jinja templating environment - - async def stop_extension(self): - ... - # Perform any required shut down steps - - -The ``ExtensionApp`` uses the following methods and properties to connect your extension to the Jupyter server. You do not need to define a ``_load_jupyter_server_extension`` function for these apps. Instead, overwrite the pieces below to add your custom settings, handlers and templates: - -Methods - -* ``initialize_settings()``: adds custom settings to the Tornado Web Application. -* ``initialize_handlers()``: appends handlers to the Tornado Web Application. -* ``initialize_templates()``: initialize the templating engine (e.g. jinja2) for your frontend. -* ``stop_extension()``: called on server shut down. - -Properties - -* ``name``: the name of the extension -* ``default_url``: the default URL for this extension—i.e. the landing page for this extension when launched from the CLI. -* ``load_other_extensions``: a boolean enabling/disabling other extensions when launching this extension directly. -* ``file_url_prefix``: the prefix URL added when opening a document directly from the command line. For example, classic Notebook uses ``/notebooks`` to open a document at http://localhost:8888/notebooks/path/to/notebook.ipynb. - -``ExtensionApp`` request handlers ---------------------------------- - -``ExtensionApp`` Request Handlers have a few extra properties. - -* ``config``: the ExtensionApp's config object. -* ``server_config``: the ServerApp's config object. -* ``name``: the name of the extension to which this handler is linked. -* ``static_url()``: a method that returns the url to static files (prefixed with ``/static/``). - -Jupyter Server provides a convenient mixin class for adding these properties to any ``JupyterHandler``. For example, the basic server extension handler in the section above becomes: - -.. code-block:: python - - from jupyter_server.base.handlers import JupyterHandler - from jupyter_server.extension.handler import ExtensionHandlerMixin - import tornado - - - class MyExtensionHandler(ExtensionHandlerMixin, JupyterHandler): - - @tornado.web.authenticated - def get(self): - ... - - @tornado.web.authenticated - def post(self): - ... - - -Jinja templating from frontend extensions ------------------------------------------ - -Many Jupyter frontend applications use Jinja for basic HTML templating. Since this is common enough, Jupyter Server provides some extra mixin that integrate Jinja with Jupyter server extensions. - -Use ``ExtensionAppJinjaMixin`` to automatically add a Jinja templating environment to an ``ExtensionApp``. This adds a ``_jinja2_env`` setting to Tornado Web Server's settings that will be used by request handlers. - -.. code-block:: python - - - from jupyter_server.extension.application import ExtensionApp, ExtensionAppJinjaMixin - - - class MyExtensionApp(ExtensionAppJinjaMixin, ExtensionApp): - ... - - -Pair the example above with ``ExtensionHandlers`` that also inherit the ``ExtensionHandlerJinjaMixin`` mixin. This will automatically load HTML templates from the Jinja templating environment created by the ``ExtensionApp``. - - -.. code-block:: python - - - from jupyter_server.base.handlers import JupyterHandler - from jupyter_server.extension.handler import ( - ExtensionHandlerMixin, - ExtensionHandlerJinjaMixin - ) - import tornado - - class MyExtensionHandler( - ExtensionHandlerMixin, - ExtensionHandlerJinjaMixin, - JupyterHandler - ): - - @tornado.web.authenticated - def get(self): - ... - - @tornado.web.authenticated - def post(self): - ... - - -.. note:: The mixin classes in this example must come before the base classes, ``ExtensionApp`` and ``ExtensionHandler``. - - -Making an ``ExtensionApp`` discoverable ---------------------------------------- - -To make an ``ExtensionApp`` discoverable by Jupyter Server, add the ``app`` key+value pair to the ``_jupyter_server_extension_points()`` function example above: - -.. code-block:: python - - from myextension import MyExtensionApp - - - def _jupyter_server_extension_points(): - """ - Returns a list of dictionaries with metadata describing - where to find the `_load_jupyter_server_extension` function. - """ - return [ - { - "module": "myextension", - "app": MyExtensionApp - } - ] - - -Launching an ``ExtensionApp`` ------------------------------ - -To launch the application, simply call the ``ExtensionApp``'s ``launch_instance`` method. - -.. code-block:: python - - launch_instance = MyFrontend.launch_instance - launch_instance() - - -To make your extension executable from anywhere on your system, point an entry-point at the ``launch_instance`` method in the extension's ``setup.py``: - -.. code-block:: python - - from setuptools import setup - - - setup( - name='myfrontend', - ... - entry_points={ - 'console_scripts': [ - 'jupyter-myextension = myextension:launch_instance' - ] - } - ) - -``ExtensionApp`` as a classic Notebook server extension -------------------------------------------------------- - -An extension that extends ``ExtensionApp`` should still work with the old Tornado server from the classic Jupyter Notebook. The ``ExtensionApp`` class -provides a method, ``load_classic_server_extension``, that handles the extension initialization. Simply define a ``load_jupyter_server_extension`` reference -pointing at the ``load_classic_server_extension`` method: - -.. code-block:: python - - # This is typically defined in the root `__init__.py` - # file of the extension package. - load_jupyter_server_extension = MyExtensionApp.load_classic_server_extension - - -If the extension is enabled, the extension will be loaded when the server starts. - - -Distributing a server extension -=============================== - -Putting it all together, authors can distribute their extension following this steps: - -1. Add a ``_jupyter_server_extension_points()`` function at the extension's root. - This function should likely live in the ``__init__.py`` found at the root of the extension package. It will look something like this: - - .. code-block:: python - - # Found in the __init__.py of package - - def _jupyter_server_extension_points(): - return [ - { - "module": "myextension.app", - "app": MyExtensionApp - } - ] - -2. Create an extension by writing a ``_load_jupyter_server_extension()`` function or subclassing ``ExtensionApp``. - This is where the extension logic will live (i.e. custom extension handlers, config, etc). See the sections above for more information on how to create an extension. - -3. Add the following JSON config file to the extension package. - The file should be named after the extension (e.g. ``myextension.json``) and saved in a subdirectory of the package with the prefix: ``jupyter-config/jupyter_server_config.d/``. The extension package will have a similar structure to this example: - - .. code-block:: - - myextension - ├── myextension/ - │ ├── __init__.py - │ └── app.py - ├── jupyter-config/ - │ └── jupyter_server_config.d/ - │ └── myextension.json - └── setup.py - - The contents of the JSON file will tell Jupyter Server to load the extension when a user installs the package: - - .. code-block:: json - - { - "ServerApp": { - "jpserver_extensions": { - "myextension": true - } - } - } - - When the extension is installed, this JSON file will be copied to the ``jupyter_server_config.d`` directory found in one of `Jupyter's paths`_. - - Users can toggle the enabling/disableing of extension using the command: - - .. code-block:: console - - jupyter server disable myextension - - which will change the boolean value in the JSON file above. - -4. Create a ``setup.py`` that automatically enables the extension. - Add a few extra lines the extension package's ``setup`` function - - .. code-block:: python - - from setuptools import setup - - setup( - name="myextension", - ... - include_package_data=True, - data_files=[ - ( - "etc/jupyter/jupyter_server_config.d", - ["jupyter-config/jupyter_server_config.d/myextension.json"] - ), - ] - - ) - - - - -.. links - -.. _`Jupyter's paths`: https://jupyter.readthedocs.io/en/latest/use/jupyter-directories.html - - -Migrating an extension to use Jupyter Server -============================================ - -If you're a developer of a `classic Notebook Server`_ extension, your extension should be able to work with *both* the classic notebook server and ``jupyter_server``. - -There are a few key steps to make this happen: - -1. Point Jupyter Server to the ``load_jupyter_server_extension`` function with a new reference name. - The ``load_jupyter_server_extension`` function was the key to loading a server extension in the classic Notebook Server. Jupyter Server expects the name of this function to be prefixed with an underscore—i.e. ``_load_jupyter_server_extension``. You can easily achieve this by adding a reference to the old function name with the new name in the same module. - - .. code-block:: python - - def load_jupyter_server_extension(nb_server_app): - ... - - # Reference the old function name with the new function name. - - _load_jupyter_server_extension = load_jupyter_server_extension - -2. Add new data files to your extension package that enable it with Jupyter Server. - This new file can go next to your classic notebook server data files. Create a new sub-directory, ``jupyter_server_config.d``, and add a new ``.json`` file there: - - .. raw:: html - -
    -        myextension
    -        ├── myextension/
    -        │   ├── __init__.py
    -        │   └── app.py
    -        ├── jupyter-config/
    -        │   └── jupyter_notebook_config.d/
    -        │       └── myextension.json
    -        │   └── jupyter_server_config.d/
    -        │       └── myextension.json
    -        └── setup.py
    -        
    - - The new ``.json`` file should look something like this (you'll notice the changes in the configured class and trait names): - - .. code-block:: json - - { - "ServerApp": { - "jpserver_extensions": { - "myextension": true - } - } - } - - Update your extension package's ``setup.py`` so that the data-files are moved into the jupyter configuration directories when users download the package. - - .. code-block:: python - - from setuptools import setup - - setup( - name="myextension", - ... - include_package_data=True, - data_files=[ - ( - "etc/jupyter/jupyter_server_config.d", - ["jupyter-config/jupyter_server_config.d/myextension.json"] - ), - ( - "etc/jupyter/jupyter_notebook_config.d", - ["jupyter-config/jupyter_notebook_config.d/myextension.json"] - ), - ] - - ) - -3. (Optional) Point extension at the new favicon location. - The favicons in the Jupyter Notebook have been moved to a new location in Jupyter Server. If your extension is using one of these icons, you'll want to add a set of redirect handlers this. (In ``ExtensionApp``, this is handled automatically). - - This usually means adding a chunk to your ``load_jupyter_server_extension`` function similar to this: - - .. code-block:: python - - def load_jupyter_server_extension(nb_server_app): - - web_app = nb_server_app.web_app - host_pattern = '.*$' - base_url = web_app.settings['base_url'] - - # Add custom extensions handler. - custom_handlers = [ - ... - ] - - # Favicon redirects. - favicon_redirects = [ - ( - url_path_join(base_url, "/static/favicons/favicon.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon.ico") - ), - ( - url_path_join(base_url, "/static/favicons/favicon-busy-1.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-1.ico")} - ), - ( - url_path_join(base_url, "/static/favicons/favicon-busy-2.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-2.ico")} - ), - ( - url_path_join(base_url, "/static/favicons/favicon-busy-3.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-busy-3.ico")} - ), - ( - url_path_join(base_url, "/static/favicons/favicon-file.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-file.ico")} - ), - ( - url_path_join(base_url, "/static/favicons/favicon-notebook.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-notebook.ico")} - ), - ( - url_path_join(base_url, "/static/favicons/favicon-terminal.ico"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon-terminal.ico")} - ), - ( - url_path_join(base_url, "/static/logo/logo.png"), - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/logo.png")} - ), - ] - - web_app.add_handlers( - host_pattern, - custom_handlers + favicon_redirects - ) - - -.. _`classic Notebook Server`: https://jupyter-notebook.readthedocs.io/en/stable/extending/handlers.html diff --git a/server/docs/source/developers/index.rst b/server/docs/source/developers/index.rst deleted file mode 100644 index b8f5140..0000000 --- a/server/docs/source/developers/index.rst +++ /dev/null @@ -1,16 +0,0 @@ -Documentation for Developers ----------------------------- - -These pages target people writing Jupyter Web applications and server extensions, or people who need to dive deeper in Jupyter Server's REST API and configuration system. - -.. toctree:: - :caption: Developers - :maxdepth: 1 - :name: developers - - dependency - rest-api - extensions - savehooks - contents - websocket-protocols diff --git a/server/docs/source/developers/rest-api.rst b/server/docs/source/developers/rest-api.rst deleted file mode 100644 index ab5b627..0000000 --- a/server/docs/source/developers/rest-api.rst +++ /dev/null @@ -1,7 +0,0 @@ -The REST API -============ - -An interactive version is available -`here `_. - -.. openapi:: ../../../jupyter_server/services/api/api.yaml diff --git a/server/docs/source/developers/savehooks.rst b/server/docs/source/developers/savehooks.rst deleted file mode 100644 index 900649d..0000000 --- a/server/docs/source/developers/savehooks.rst +++ /dev/null @@ -1,84 +0,0 @@ -File save hooks -=============== - -You can configure functions that are run whenever a file is saved. There are -two hooks available: - -* ``ContentsManager.pre_save_hook`` runs on the API path and model with - content. This can be used for things like stripping output that people don't - like adding to VCS noise. -* ``FileContentsManager.post_save_hook`` runs on the filesystem path and model - without content. This could be used to commit changes after every save, for - instance. - -They are both called with keyword arguments:: - - pre_save_hook(model=model, path=path, contents_manager=cm) - post_save_hook(model=model, os_path=os_path, contents_manager=cm) - -Examples --------- - -These can both be added to :file:`jupyter_server_config.py`. - -A pre-save hook for stripping output:: - - def scrub_output_pre_save(model, **kwargs): - """scrub output before saving notebooks""" - # only run on notebooks - if model['type'] != 'notebook': - return - # only run on nbformat v4 - if model['content']['nbformat'] != 4: - return - - for cell in model['content']['cells']: - if cell['cell_type'] != 'code': - continue - cell['outputs'] = [] - cell['execution_count'] = None - - c.FileContentsManager.pre_save_hook = scrub_output_pre_save - -A post-save hook to make a script equivalent whenever the notebook is saved -(replacing the ``--script`` option in older versions of the notebook): - -.. code-block:: python - - import io - import os - from jupyter_server.utils import to_api_path - - _script_exporter = None - - def script_post_save(model, os_path, contents_manager, **kwargs): - """convert notebooks to Python script after save with nbconvert - - replaces `ipython notebook --script` - """ - from nbconvert.exporters.script import ScriptExporter - - if model['type'] != 'notebook': - return - - global _script_exporter - - if _script_exporter is None: - _script_exporter = ScriptExporter(parent=contents_manager) - - log = contents_manager.log - - base, ext = os.path.splitext(os_path) - py_fname = base + '.py' - script, resources = _script_exporter.from_filename(os_path) - script_fname = base + resources.get('output_extension', '.txt') - log.info("Saving script /%s", to_api_path(script_fname, contents_manager.root_dir)) - - with io.open(script_fname, 'w', encoding='utf-8') as f: - f.write(script) - - c.FileContentsManager.post_save_hook = script_post_save - - -This could be a simple call to ``jupyter nbconvert --to script``, but spawning -the subprocess every time is quite slow. diff --git a/server/docs/source/developers/websocket-protocols.rst b/server/docs/source/developers/websocket-protocols.rst deleted file mode 100644 index e4cf093..0000000 --- a/server/docs/source/developers/websocket-protocols.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. _websocket_protocols: - -WebSocket kernel wire protocols -=============================== - -The Jupyter Server needs to pass messages between kernels and the Jupyter web application. Kernels use ZeroMQ sockets, and the web application uses a WebSocket. - -ZeroMQ wire protocol --------------------- - -The kernel wire protocol over ZeroMQ takes advantage of multipart messages, allowing to decompose a message into parts and to send and receive them unmerged. The following table shows the message format (the beginning has been omitted for clarity): - -.. list-table:: Format of a kernel message over ZeroMQ socket (indices refer to parts, not bytes) - :header-rows: 1 - - * - ... - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - ... - * - ... - - header - - parent_header - - metadata - - content - - buffer_0 - - buffer_1 - - ... - -See also the `Jupyter Client documentation `_. - -Note that a set of ZeroMQ sockets, one for each channel (shell, iopub, etc.), are multiplexed into one WebSocket. Thus, the channel name must be encoded in WebSocket messages. - -WebSocket protocol negotiation ------------------------------- - -When opening a WebSocket, the Jupyter web application can optionally provide a list of subprotocols it supports (see e.g. the `MDN documentation `_). If nothing is provided (empty list), then the Jupyter Server assumes the default protocol will be used. Otherwise, the Jupyter Server must select one of the provided subprotocols, or none of them. If none of them is selected, the Jupyter Server must reply with an empty string, which means that the default protocol will be used. - -Default WebSocket protocol --------------------------- - -The Jupyter Server must support the default protocol, in which a kernel message is serialized over WebSocket as follows: - -.. list-table:: Format of a kernel message over WebSocket (indices refer to bytes) - :header-rows: 1 - - * - 0 - - 4 - - 8 - - ... - - offset_0 - - offset_1 - - offset_2 - - ... - * - offset_0 - - offset_1 - - offset_2 - - ... - - msg - - buffer_0 - - buffer_1 - - ... - -Where: - -* ``offset_0`` is the position of the kernel message (``msg``) from the beginning of this message, in bytes. -* ``offset_1`` is the position of the first binary buffer (``buffer_0``) from the beginning of this message, in bytes (optional). -* ``offset_2`` is the position of the second binary buffer (``buffer_1``) from the beginning of this message, in bytes (optional). -* ``msg`` is the kernel message, excluding binary buffers and including the channel name, as a UTF8-encoded stringified JSON. -* ``buffer_0`` is the first binary buffer (optional). -* ``buffer_1`` is the second binary buffer (optional). - -The message can be deserialized by parsing ``msg`` as a JSON object (after decoding it to a string): - -.. code-block:: python - - msg = { - 'channel': channel, - 'header': header, - 'parent_header': parent_header, - 'metadata': metadata, - 'content': content - } - -Then retrieving the channel name, and updating with the buffers, if any: - -.. code-block:: python - - buffers = { - [ - buffer_0, - buffer_1 - # ... - ] - } - -``v1.kernel.websocket.jupyter.org`` protocol --------------------------------------------- - -The Jupyter Server can optionally support the ``v1.kernel.websocket.jupyter.org`` protocol, in which a kernel message is serialized over WebSocket as follows: - -.. list-table:: Format of a kernel message over WebSocket (indices refer to bytes) - :header-rows: 1 - - * - 0 - - 8 - - 16 - - ... - - 8*offset_number - - offset_0 - - offset_1 - - offset_2 - - offset_3 - - offset_4 - - offset_5 - - offset_6 - - ... - * - offset_number - - offset_0 - - offset_1 - - ... - - offset_n - - channel - - header - - parent_header - - metadata - - content - - buffer_0 - - buffer_1 - - ... - -Where: - -* ``offset_number`` is a 64-bit (little endian) unsigned integer. -* ``offset_0`` to ``offset_n`` are 64-bit (little endian) unsigned integers (with ``n=offset_number-1``). -* ``channel`` is a UTF-8 encoded string containing the channel for the message (shell, iopub, etc.). -* ``header``, ``parent_header``, ``metadata``, and ``content`` are UTF-8 encoded JSON text representing the given part of a message in the Jupyter message protocol. -* ``offset_n`` is the number of bytes in the message. -* The message can be deserialized from the ``bin_msg`` serialized message as follows (Python code): - -.. code-block:: python - - import json - channel = bin_msg[offset_0:offset_1].decode('utf-8') - header = json.loads(bin_msg[offset_1:offset_2]) - parent_header = json.loads(bin_msg[offset_2:offset_3]) - metadata = json.loads(bin_msg[offset_3:offset_4]) - content = json.loads(bin_msg[offset_4:offset_5]) - buffer_0 = bin_msg[offset_5:offset_6] - buffer_1 = bin_msg[offset_6:offset_7] - # ... - last_buffer = bin_msg[offset_n_minus_1:offset_n] diff --git a/server/docs/source/index.rst b/server/docs/source/index.rst deleted file mode 100644 index 11922b9..0000000 --- a/server/docs/source/index.rst +++ /dev/null @@ -1,46 +0,0 @@ -Welcome! -======== - -You've landed on the documentation pages for the **Jupyter Server** Project. Some other pages you may have been looking for: - -* `Jupyter Server Github Repo `_, the source code we describe in this code. -* `Jupyter Notebook Github Repo `_ , the source code for the classic Notebook. -* `JupyterLab Github Repo `_, the JupyterLab server wich runs on the Jupyter Server. - - -Introduction ------------- - -Jupyter Server is the backend—the core services, APIs, and `REST endpoints`_—to Jupyter web applications. - -.. note:: - - Jupyter Server is a replacement for the Tornado Web Server in `Jupyter Notebook`_. Jupyter web applications should move to using Jupyter Server. For help, see the :ref:`migrate_from_notebook` page. - -.. _Tornado: https://www.tornadoweb.org/en/stable/ -.. _Jupyter Notebook: https://github.com/jupyter/notebook -.. _REST endpoints: https://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/jupyter_server/main/jupyter_server/services/api/api.yaml - -Who's this for? ---------------- - -The Jupyter Server is a highly technical piece of the Jupyter Stack, so we've separated documentation to help specific personas: - -1. :ref:`Users `: people using Jupyter web applications. -2. :ref:`Operators `: people deploying or serving Jupyter web applications to others. -3. :ref:`Developers `: people writing Jupyter Server extensions and web applications. -4. :ref:`Contributors `: people contributing directly to the Jupyter Server library. - -If you finds gaps in our documentation, please open an issue (or better, a pull request) on the Jupyter Server `Github repo `_. - -Table of Contents ------------------ - -.. toctree:: - :maxdepth: 2 - - Users - Operators - Developers - Contributors - Other diff --git a/server/docs/source/operators/configuring-extensions.rst b/server/docs/source/operators/configuring-extensions.rst deleted file mode 100644 index 839ae72..0000000 --- a/server/docs/source/operators/configuring-extensions.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. _configure-multiple-extensions: - -Configuring Extensions -====================== - -Some Jupyter Server extensions are also configurable applications. There are two ways to configure such extensions: i) pass arguments to the extension's entry point or ii) list configurable options in a Jupyter config file. - -Jupyter Server looks for an extension's config file in a set of specific paths. Use the ``jupyter`` entry point to list these paths: - -.. code-block:: console - - > jupyter --paths - - config: - /Users/username/.jupyter - /usr/local/etc/jupyter - /etc/jupyter - data: - /Users/username/Library/Jupyter - /usr/local/share/jupyter - /usr/share/jupyter - runtime: - /Users/username/Library/Jupyter/runtime - - -Extension config from file --------------------------- - -Jupyter Server expects the file to be named after the extension's name like so: ``jupyter_{name}_config``. For example, the Jupyter Notebook's config file is ``jupyter_notebook_config``. - -Configuration files can be Python or JSON files. - -In Python config files, each trait will be prefixed with ``c.`` that links the trait to the config loader. For example, Jupyter Notebook config might look like: - -.. code-block:: python - - # jupyter_notebook_config.py - - c.NotebookApp.mathjax_enabled = False - - -A Jupyter Server will automatically load config for each enabled extension. You can configure each extension by creating their corresponding Jupyter config file. - - -Extension config on the command line ------------------------------------- - -Server extension applications can also be configured from the command line, and multiple extension can be configured at the same time. Simply pass the traits (with their appropriate prefix) to the ``jupyter server`` entrypoint, e.g.: - -.. code-block:: console - - > jupyter server --ServerApp.port=9999 --MyExtension1.trait=False --MyExtension2.trait=True - - -This will also work with any extension entrypoints that allow other extensions to run side-by-side, e.g.: - -.. code-block:: console - - > jupyter myextension --ServerApp.port=9999 --MyExtension1.trait=False --MyExtension2.trait=True diff --git a/server/docs/source/operators/index.rst b/server/docs/source/operators/index.rst deleted file mode 100644 index 41354bc..0000000 --- a/server/docs/source/operators/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -Documentation for Operators -=========================== - -These pages are targeted at people using, configuring, and/or deploying multiple Jupyter Web Application with Jupyter Server. - -.. toctree:: - :caption: Operators - :maxdepth: 1 - :name: operators - - multiple-extensions - configuring-extensions - migrate-from-nbserver - public-server - security diff --git a/server/docs/source/operators/ipython_security.asc b/server/docs/source/operators/ipython_security.asc deleted file mode 100644 index 9543681..0000000 --- a/server/docs/source/operators/ipython_security.asc +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2.0.22 (GNU/Linux) - -mQINBFMx2LoBEAC9xU8JiKI1VlCJ4PT9zqhU5nChQZ06/bj1BBftiMJG07fdGVO0 -ibOn4TrCoRYaeRlet0UpHzxT4zDa5h3/usJaJNTSRwtWePw2o7Lik8J+F3LionRf -8Jz81WpJ+81Klg4UWKErXjBHsu/50aoQm6ZNYG4S2nwOmMVEC4nc44IAA0bb+6kW -saFKKzEDsASGyuvyutdyUHiCfvvh5GOC2h9mXYvl4FaMW7K+d2UgCYERcXDNy7C1 -Bw+uepQ9ELKdG4ZpvonO6BNr1BWLln3wk93AQfD5qhfsYRJIyj0hJlaRLtBU3i6c -xs+gQNF4mPmybpPSGuOyUr4FYC7NfoG7IUMLj+DYa6d8LcMJO+9px4IbdhQvzGtC -qz5av1TX7/+gnS4L8C9i1g8xgI+MtvogngPmPY4repOlK6y3l/WtxUPkGkyYkn3s -RzYyE/GJgTwuxFXzMQs91s+/iELFQq/QwmEJf+g/QYfSAuM+lVGajEDNBYVAQkxf -gau4s8Gm0GzTZmINilk+7TxpXtKbFc/Yr4A/fMIHmaQ7KmJB84zKwONsQdVv7Jjj -0dpwu8EIQdHxX3k7/Q+KKubEivgoSkVwuoQTG15X9xrOsDZNwfOVQh+JKazPvJtd -SNfep96r9t/8gnXv9JI95CGCQ8lNhXBUSBM3BDPTbudc4b6lFUyMXN0mKQARAQAB -tCxJUHl0aG9uIFNlY3VyaXR5IFRlYW0gPHNlY3VyaXR5QGlweXRob24ub3JnPokC -OAQTAQIAIgUCUzHYugIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQEwJc -LcmZYkjuXg//R/t6nMNQmf9W1h52IVfUbRAVmvZ5d063hQHKV2dssxtnA2dRm/x5 -JZu8Wz7ZrEZpyqwRJO14sxN1/lC3v+zs9XzYXr2lBTZuKCPIBypYVGIynCuWJBQJ -rWnfG4+u1RHahnjqlTWTY1C/le6v7SjAvCb6GbdA6k4ZL2EJjQlRaHDmzw3rV/+l -LLx6/tYzIsotuflm/bFumyOMmpQQpJjnCkWIVjnRICZvuAn97jLgtTI0+0Rzf4Zb -k2BwmHwDRqWCTTcRI9QvTl8AzjW+dNImN22TpGOBPfYj8BCZ9twrpKUbf+jNqJ1K -THQzFtpdJ6SzqiFVm74xW4TKqCLkbCQ/HtVjTGMGGz/y7KTtaLpGutQ6XE8SSy6P -EffSb5u+kKlQOWaH7Mc3B0yAojz6T3j5RSI8ts6pFi6pZhDg9hBfPK2dT0v/7Mkv -E1Z7q2IdjZnhhtGWjDAMtDDn2NbY2wuGoa5jAWAR0WvIbEZ3kOxuLE5/ZOG1FyYm -noJRliBz7038nT92EoD5g1pdzuxgXtGCpYyyjRZwaLmmi4CvA+oThKmnqWNY5lyY -ricdNHDiyEXK0YafJL1oZgM86MSb0jKJMp5U11nUkUGzkroFfpGDmzBwAzEPgeiF -40+qgsKB9lqwb3G7PxvfSi3XwxfXgpm1cTyEaPSzsVzve3d1xeqb7Yq5Ag0EUzHY -ugEQALQ5FtLdNoxTxMsgvrRr1ejLiUeRNUfXtN1TYttOfvAhfBVnszjtkpIW8DCB -JF/bA7ETiH8OYYn/Fm6MPI5H64IHEncpzxjf57jgpXd9CA9U2OMk/P1nve5zYchP -QmP2fJxeAWr0aRH0Mse5JS5nCkh8Xv4nAjsBYeLTJEVOb1gPQFXOiFcVp3gaKAzX -GWOZ/mtG/uaNsabH/3TkcQQEgJefd11DWgMB7575GU+eME7c6hn3FPITA5TC5HUX -azvjv/PsWGTTVAJluJ3fUDvhpbGwYOh1uV0rB68lPpqVIro18IIJhNDnccM/xqko -4fpJdokdg4L1wih+B04OEXnwgjWG8OIphR/oL/+M37VV2U7Om/GE6LGefaYccC9c -tIaacRQJmZpG/8RsimFIY2wJ07z8xYBITmhMmOt0bLBv0mU0ym5KH9Dnru1m9QDO -AHwcKrDgL85f9MCn+YYw0d1lYxjOXjf+moaeW3izXCJ5brM+MqVtixY6aos3YO29 -J7SzQ4aEDv3h/oKdDfZny21jcVPQxGDui8sqaZCi8usCcyqWsKvFHcr6vkwaufcm -3Knr2HKVotOUF5CDZybopIz1sJvY/5Dx9yfRmtivJtglrxoDKsLi1rQTlEQcFhCS -ACjf7txLtv03vWHxmp4YKQFkkOlbyhIcvfPVLTvqGerdT2FHABEBAAGJAh8EGAEC -AAkFAlMx2LoCGwwACgkQEwJcLcmZYkgK0BAAny0YUugpZldiHzYNf8I6p2OpiDWv -ZHaguTTPg2LJSKaTd+5UHZwRFIWjcSiFu+qTGLNtZAdcr0D5f991CPvyDSLYgOwb -Jm2p3GM2KxfECWzFbB/n/PjbZ5iky3+5sPlOdBR4TkfG4fcu5GwUgCkVe5u3USAk -C6W5lpeaspDz39HAPRSIOFEX70+xV+6FZ17B7nixFGN+giTpGYOEdGFxtUNmHmf+ -waJoPECyImDwJvmlMTeP9jfahlB6Pzaxt6TBZYHetI/JR9FU69EmA+XfCSGt5S+0 -Eoc330gpsSzo2VlxwRCVNrcuKmG7PsFFANok05ssFq1/Djv5rJ++3lYb88b8HSP2 -3pQJPrM7cQNU8iPku9yLXkY5qsoZOH+3yAia554Dgc8WBhp6fWh58R0dIONQxbbo -apNdwvlI8hKFB7TiUL6PNShE1yL+XD201iNkGAJXbLMIC1ImGLirUfU267A3Cop5 -hoGs179HGBcyj/sKA3uUIFdNtP+NndaP3v4iYhCitdVCvBJMm6K3tW88qkyRGzOk -4PW422oyWKwbAPeMk5PubvEFuFAIoBAFn1zecrcOg85RzRnEeXaiemmmH8GOe1Xu -Kh+7h8XXyG6RPFy8tCcLOTk+miTqX+4VWy+kVqoS2cQ5IV8WsJ3S7aeIy0H89Z8n -5vmLc+Ibz+eT+rM= -=XVDe ------END PGP PUBLIC KEY BLOCK----- diff --git a/server/docs/source/operators/migrate-from-nbserver.rst b/server/docs/source/operators/migrate-from-nbserver.rst deleted file mode 100644 index d635d3b..0000000 --- a/server/docs/source/operators/migrate-from-nbserver.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _migrate_from_notebook: - -Migrating from Notebook Server -============================== - -To migrate from notebook server to plain jupyter server, follow these steps: - -- Rename your ``jupyter_notebook_config.py`` file to ``jupyter_server_config.py``. -- Rename all ``c.NotebookApp`` traits to ``c.ServerApp``. - -For example if you have the following ``jupyter_notebook_config.py``. - -.. code-block:: python - - c.NotebookApp.allow_credentials = False - c.NotebookApp.port = 8889 - c.NotebookApp.password_required = True - - -You will have to create the following ``jupyter_server_config.py`` file. - -.. code-block:: python - - c.ServerApp.allow_credentials = False - c.ServerApp.port = 8889 - c.ServerApp.password_required = True - - -Running Jupyter Notebook on Jupyter Server -========================================== - -If you want to switch to Jupyter Server, but you still want to serve `Jupyter Notebook `_ to users, you can try `NBClassic `_. - -NBClassic is a Jupyter Server extension that serves the Notebook frontend (i.e. all static assets) on top of Jupyter Server. It even loads Jupyter Notebook's config files. - -.. warning:: NBClassic will only work for a limited time. Jupyter Server is likely to evolve beyond a point where Jupyter Notebook frontend will no longer work with the underlying server. Consider switching to `JupyterLab `_ or `nteract `_ where there is active development happening. diff --git a/server/docs/source/operators/multiple-extensions.rst b/server/docs/source/operators/multiple-extensions.rst deleted file mode 100644 index 0579e8e..0000000 --- a/server/docs/source/operators/multiple-extensions.rst +++ /dev/null @@ -1,89 +0,0 @@ - -.. _managing-multiple-extensions: - -Managing multiple extensions ----------------------------- - -One of the major benefits of Jupyter Server is that you can run serve multiple Jupyter frontend applications above the same Tornado web server. That's because every Jupyter frontend application is now a server extension. When you run a Jupyter Server will multiple extensions enabled, each extension appends its own set of handlers and static assets to the server. - -Listing extensions -~~~~~~~~~~~~~~~~~~ - -When you install a Jupyter Server extension, it *should* automatically add itself to your list of enabled extensions. You can see a list of installed extensions by calling: - -.. code-block:: console - - > jupyter server extension list - - config dir: /Users/username/etc/jupyter - myextension enabled - - Validating myextension... - myextension OK - -Enabling/disabling extensions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You enable/disable an extension using the following commands: - -.. code-block:: console - - > jupyter server extension enable myextension - - Enabling: myextension - - Validating myextension... - myextension OK - - Extension successfully enabled. - - - > jupyter server extension disable myextension - - Disabling: jupyter_home - - Validating jupyter_home... - jupyter_home OK - - Extension successfully disabled. - - -Running an extensions from its entrypoint -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Extensions that are also Jupyter applications (i.e. Notebook, JupyterLab, Voila, etc.) can be launched -from a CLI entrypoint. For example, launch Jupyter Notebook using: - -.. code-block:: console - - > jupyter notebook - - -Jupyter Server will automatically start a server and the browser will be routed to Jupyter Notebook's default URL (typically, ``/tree``). - -Other enabled extension will still be available to the user. The entrypoint simply offers a more direct (backwards compatible) launching mechanism. - -Launching a server with multiple extensions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If multiple extensions are enabled, a Jupyter Server can be launched directly: - -.. code-block:: console - - > jupyter server - - [I 2020-03-23 15:44:53.290 ServerApp] Serving notebooks from local directory: /Users/username/path - [I 2020-03-23 15:44:53.290 ServerApp] Jupyter Server 0.3.0.dev is running at: - [I 2020-03-23 15:44:53.290 ServerApp] http://localhost:8888/?token=<...> - [I 2020-03-23 15:44:53.290 ServerApp] or http://127.0.0.1:8888/?token=<...> - [I 2020-03-23 15:44:53.290 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). - [I 2020-03-23 15:44:53.290 ServerApp] Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at https://jupyter.org/community.html. - [C 2020-03-23 15:44:53.296 ServerApp] - - To access the server, open this file in a browser: - file:///Users/username/pathjpserver-####-open.html - Or copy and paste one of these URLs: - http://localhost:8888/?token=<...> - or http://127.0.0.1:8888/?token=<...> - - -Extensions can also be enabled manually from the Jupyter Server entrypoint using the ``jpserver_extensions`` trait: - -.. code-block:: console - - > jupyter server --ServerApp.jpserver_extensions='{"myextension":{"enabled": True}}' diff --git a/server/docs/source/operators/public-server.rst b/server/docs/source/operators/public-server.rst deleted file mode 100644 index cfe75fd..0000000 --- a/server/docs/source/operators/public-server.rst +++ /dev/null @@ -1,443 +0,0 @@ -.. _working_remotely: - -Running a public Jupyter Server -=============================== - - -The Jupyter Server uses a :ref:`two-process kernel -architecture ` based on ZeroMQ_, as well as Tornado_ for -serving HTTP requests. - -.. note:: - By default, Jupyter Server runs locally at 127.0.0.1:8888 - and is accessible only from `localhost`. You may access the - server from the browser using `http://127.0.0.1:8888`. - -This document describes how you can -:ref:`secure a Jupyter server ` and how to -:ref:`run it on a public interface `. - -.. important:: - - **This is not the multi-user server you are looking for**. This document - describes how you can run a public server with a single user. This should - only be done by someone who wants remote access to their personal machine. - Even so, doing this requires a thorough understanding of the set-ups - limitations and security implications. If you allow multiple users to - access a Jupyter server as it is described in this document, their - commands may collide, clobber and overwrite each other. - - If you want a multi-user server, the official solution is JupyterHub_. - To use JupyterHub, you need a Unix server (typically Linux) running - somewhere that is accessible to your users on a network. This may run over - the public internet, but doing so introduces additional - `security concerns `_. - - - -.. _ZeroMQ: https://zeromq.org/ - -.. _Tornado: with Found to http://www.tornadoweb.org/en/stable/ - -.. _JupyterHub: https://jupyterhub.readthedocs.io/en/latest/ - -.. _Jupyter_server_security: - -Securing a Jupyter server -------------------------- - -You can protect your Jupyter server with a simple single password. As of -notebook 5.0 this can be done automatically. To set up a password manually you -can configure the :attr:`ServerApp.password` setting in -:file:`jupyter_server_config.py`. - - -Prerequisite: A Jupyter server configuration file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Check to see if you have a Jupyter server configuration file, -:file:`jupyter_server_config.py`. The default location for this file -is your Jupyter folder located in your home directory: - - - Windows: :file:`C:\\Users\\USERNAME\\.jupyter\\jupyter_server_config.py` - - OS X: :file:`/Users/USERNAME/.jupyter/jupyter_server_config.py` - - Linux: :file:`/home/USERNAME/.jupyter/jupyter_server_config.py` - -If you don't already have a Jupyter folder, or if your Jupyter folder doesn't contain -a Jupyter server configuration file, run the following command:: - - $ jupyter server --generate-config - -This command will create the Jupyter folder if necessary, and create a Jupyter -server configuration file, :file:`jupyter_server_config.py`, in this folder. - - -Automatic Password setup -~~~~~~~~~~~~~~~~~~~~~~~~ - -As of notebook 5.3, the first time you log-in using a token, the server should -give you the opportunity to setup a password from the user interface. - -You will be presented with a form asking for the current _token_, as well as -your _new_ _password_ ; enter both and click on ``Login and setup new password``. - -Next time you need to log in you'll be able to use the new password instead of -the login token, otherwise follow the procedure to set a password from the -command line. - -The ability to change the password at first login time may be disabled by -integrations by setting the ``--ServerApp.allow_password_change=False`` - - -Starting at notebook version 5.0, you can enter and store a password for your -server with a single command. :command:`jupyter server password` will -prompt you for your password and record the hashed password in your -:file:`jupyter_server_config.json`. - -.. code-block:: bash - - $ jupyter server password - Enter password: **** - Verify password: **** - [JupyterPasswordApp] Wrote hashed password to /Users/you/.jupyter/jupyter_server_config.json - -This can be used to reset a lost password; or if you believe your credentials -have been leaked and desire to change your password. Changing your password will -invalidate all logged-in sessions after a server restart. - -.. _hashed-pw: - -Preparing a hashed password -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can prepare a hashed password manually, using the function -:func:`notebook.auth.security.passwd`: - -.. code-block:: ipython - - In [1]: from jupyter_server.auth import passwd - In [2]: passwd() - Enter password: - Verify password: - Out[2]: 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed' - -.. caution:: - - :func:`~notebook.auth.security.passwd` when called with no arguments - will prompt you to enter and verify your password such as - in the above code snippet. Although the function can also - be passed a string as an argument such as ``passwd('mypassword')``, please - **do not** pass a string as an argument inside an IPython session, as it - will be saved in your input history. - -Adding hashed password to your notebook configuration file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can then add the hashed password to your -:file:`jupyter_server_config.py`. The default location for this file -:file:`jupyter_server_config.py` is in your Jupyter folder in your home -directory, ``~/.jupyter``, e.g.:: - - c.ServerApp.password = u'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed' - -Automatic password setup will store the hash in ``jupyter_server_config.json`` -while this method stores the hash in ``jupyter_server_config.py``. The ``.json`` -configuration options take precedence over the ``.py`` one, thus the manual -password may not take effect if the Json file has a password set. - - -Using SSL for encrypted communication -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When using a password, it is a good idea to also use SSL with a web -certificate, so that your hashed password is not sent unencrypted by your -browser. - -.. important:: - Web security is rapidly changing and evolving. We provide this document - as a convenience to the user, and recommend that the user keep current on - changes that may impact security, such as new releases of OpenSSL. - The Open Web Application Security Project (`OWASP`_) website is a good resource - on general security issues and web practices. - -You can start the notebook to communicate via a secure protocol mode by setting -the ``certfile`` option to your self-signed certificate, i.e. ``mycert.pem``, -with the command:: - - $ jupyter server --certfile=mycert.pem --keyfile mykey.key - -.. tip:: - - A self-signed certificate can be generated with ``openssl``. For example, - the following command will create a certificate valid for 365 days with - both the key and certificate data written to the same file:: - - $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mykey.key -out mycert.pem - -When starting the notebook server, your browser may warn that your self-signed -certificate is insecure or unrecognized. If you wish to have a fully -compliant self-signed certificate that will not raise warnings, it is possible -(but rather involved) to create one, as explained in detail in this -`tutorial`_. Alternatively, you may use `Let's Encrypt`_ to acquire a free SSL -certificate and follow the steps in :ref:`using-lets-encrypt` to set up a -public server. - -.. _OWASP: https://www.owasp.org/index.php/Main_Page -.. _tutorial: https://arstechnica.com/information-technology/2009/12/how-to-get-set-with-a-secure-sertificate-for-free/ - -.. _jupyter_public_server: - -Running a public notebook server --------------------------------- - -If you want to access your notebook server remotely via a web browser, -you can do so by running a public notebook server. For optimal security -when running a public notebook server, you should first secure the -server with a password and SSL/HTTPS as described in -:ref:`jupyter_server_security`. - -Start by creating a certificate file and a hashed password, as explained in -:ref:`jupyter_server_security`. - -If you don't already have one, create a -config file for the notebook using the following command line:: - - $ jupyter server --generate-config - -In the ``~/.jupyter`` directory, edit the notebook config file, -``jupyter_server_config.py``. By default, the notebook config file has -all fields commented out. The minimum set of configuration options that -you should uncomment and edit in :file:`jupyter_server_config.py` is the -following:: - - # Set options for certfile, ip, password, and toggle off - # browser auto-opening - c.ServerApp.certfile = u'/absolute/path/to/your/certificate/mycert.pem' - c.ServerApp.keyfile = u'/absolute/path/to/your/certificate/mykey.key' - # Set ip to '*' to bind on all interfaces (ips) for the public server - c.ServerApp.ip = '*' - c.ServerApp.password = u'sha1:bcd259ccf...' - c.ServerApp.open_browser = False - - # It is a good idea to set a known, fixed port for server access - c.ServerApp.port = 9999 - -You can then start the notebook using the ``jupyter server`` command. - -.. _using-lets-encrypt: - -Using Let's Encrypt -~~~~~~~~~~~~~~~~~~~ -`Let's Encrypt`_ provides free SSL/TLS certificates. You can also set up a -public server using a `Let's Encrypt`_ certificate. - -:ref:`jupyter_public_server` will be similar when using a Let's Encrypt -certificate with a few configuration changes. Here are the steps: - -1. Create a `Let's Encrypt certificate `_. -2. Use :ref:`hashed-pw` to create one. -3. If you don't already have config file for the notebook, create one - using the following command: - - .. code-block:: bash - - $ jupyter server --generate-config - -4. In the ``~/.jupyter`` directory, edit the notebook config file, -``jupyter_server_config.py``. By default, the notebook config file has -all fields commented out. The minimum set of configuration options that -you should to uncomment and edit in :file:`jupyter_server_config.py` is the -following:: - - # Set options for certfile, ip, password, and toggle off - # browser auto-opening - c.ServerApp.certfile = u'/absolute/path/to/your/certificate/fullchain.pem' - c.ServerApp.keyfile = u'/absolute/path/to/your/certificate/privkey.pem' - # Set ip to '*' to bind on all interfaces (ips) for the public server - c.ServerApp.ip = '*' - c.ServerApp.password = u'sha1:bcd259ccf...' - c.ServerApp.open_browser = False - - # It is a good idea to set a known, fixed port for server access - c.ServerApp.port = 9999 - -You can then start the notebook using the ``jupyter server`` command. - -.. important:: - - **Use 'https'.** - Keep in mind that when you enable SSL support, you must access the - notebook server over ``https://``, not over plain ``http://``. The startup - message from the server prints a reminder in the console, but *it is easy - to overlook this detail and think the server is for some reason - non-responsive*. - - **When using SSL, always access the notebook server with 'https://'.** - -You may now access the public server by pointing your browser to -``https://your.host.com:9999`` where ``your.host.com`` is your public server's -domain. - -.. _`Let's Encrypt`: https://letsencrypt.org - - -Firewall Setup -~~~~~~~~~~~~~~ - -To function correctly, the firewall on the computer running the jupyter -notebook server must be configured to allow connections from client -machines on the access port ``c.ServerApp.port`` set in -:file:`jupyter_server_config.py` to allow connections to the -web interface. The firewall must also allow connections from -127.0.0.1 (localhost) on ports from 49152 to 65535. -These ports are used by the server to communicate with the notebook kernels. -The kernel communication ports are chosen randomly by ZeroMQ, and may require -multiple connections per kernel, so a large range of ports must be accessible. - -Running the notebook with a customized URL prefix -------------------------------------------------- - -The notebook dashboard, which is the landing page with an overview -of the notebooks in your working directory, is typically found and accessed -at the default URL ``http://localhost:8888/``. - -If you prefer to customize the URL prefix for the notebook dashboard, you can -do so through modifying ``jupyter_server_config.py``. For example, if you -prefer that the notebook dashboard be located with a sub-directory that -contains other ipython files, e.g. ``http://localhost:8888/ipython/``, -you can do so with configuration options like the following (see above for -instructions about modifying ``jupyter_server_config.py``): - -.. code-block:: python - - c.ServerApp.base_url = '/ipython/' - -Embedding the notebook in another website ------------------------------------------ - -Sometimes you may want to embed the notebook somewhere on your website, -e.g. in an IFrame. To do this, you may need to override the -Content-Security-Policy to allow embedding. Assuming your website is at -`https://mywebsite.example.com`, you can embed the notebook on your website -with the following configuration setting in -:file:`jupyter_server_config.py`: - -.. code-block:: python - - c.ServerApp.tornado_settings = { - 'headers': { - 'Content-Security-Policy': "frame-ancestors https://mywebsite.example.com 'self' " - } - } - -When embedding the notebook in a website using an iframe, -consider putting the notebook in single-tab mode. -Since the notebook opens some links in new tabs by default, -single-tab mode keeps the notebook from opening additional tabs. -Adding the following to :file:`~/.jupyter/custom/custom.js` will enable -single-tab mode: - -.. code-block:: javascript - - define(['base/js/namespace'], function(Jupyter){ - Jupyter._target = '_self'; - }); - - -Using a gateway server for kernel management --------------------------------------------- - -You are now able to redirect the management of your kernels to a Gateway Server -(i.e., `Jupyter Kernel Gateway `_ or -`Jupyter Enterprise Gateway `_) -simply by specifying a Gateway url via the following command-line option: - - .. code-block:: bash - - $ jupyter notebook --gateway-url=http://my-gateway-server:8888 - -the environment: - - .. code-block:: bash - - JUPYTER_GATEWAY_URL=http://my-gateway-server:8888 - -or in :file:`jupyter_notebook_config.py`: - - .. code-block:: python - - c.GatewayClient.url = http://my-gateway-server:8888 - -When provided, all kernel specifications will be retrieved from the specified Gateway server and all -kernels will be managed by that server. This option enables the ability to target kernel processes -against managed clusters while allowing for the notebook's management to remain local to the Notebook -server. - -Known issues ------------- - -Proxies -~~~~~~~ - -When behind a proxy, especially if your system or browser is set to autodetect -the proxy, the notebook web application might fail to connect to the server's -websockets, and present you with a warning at startup. In this case, you need -to configure your system not to use the proxy for the server's address. - -For example, in Firefox, go to the Preferences panel, Advanced section, -Network tab, click 'Settings...', and add the address of the Jupyter server -to the 'No proxy for' field. - -Content-Security-Policy (CSP) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Certain `security guidelines -`_ -recommend that servers use a Content-Security-Policy (CSP) header to prevent -cross-site scripting vulnerabilities, specifically limiting to ``default-src: -https:`` when possible. This directive causes two problems with Jupyter. -First, it disables execution of inline javascript code, which is used -extensively by Jupyter. Second, it limits communication to the https scheme, -and prevents WebSockets from working because they communicate via the wss -scheme (or ws for insecure communication). Jupyter uses WebSockets for -interacting with kernels, so when you visit a server with such a CSP, your -browser will block attempts to use wss, which will cause you to see -"Connection failed" messages from jupyter notebooks, or simply no response -from jupyter terminals. By looking in your browser's javascript console, you -can see any error messages that will explain what is failing. - -To avoid these problem, you need to add ``'unsafe-inline'`` and ``connect-src -https: wss:`` to your CSP header, at least for pages served by jupyter. (That -is, you can leave your CSP unchanged for other parts of your website.) Note -that multiple CSP headers are allowed, but successive CSP headers can only -restrict the policy; they cannot loosen it. For example, if your server sends -both of these headers - - Content-Security-Policy "default-src https: 'unsafe-inline'" - Content-Security-Policy "connect-src https: wss:" - -the first policy will already eliminate wss connections, so the second has no -effect. Therefore, you can't simply add the second header; you have to -actually modify your CSP header to look more like this: - - Content-Security-Policy "default-src https: 'unsafe-inline'; connect-src https: wss:" - - - -Docker CMD -~~~~~~~~~~ - -Using ``jupyter server`` as a -`Docker CMD `_ results in -kernels repeatedly crashing, likely due to a lack of `PID reaping -`_. -To avoid this, use the `tini `_ ``init`` as your -Dockerfile `ENTRYPOINT`:: - - # Add Tini. Tini operates as a process subreaper for jupyter. This prevents - # kernel crashes. - ENV TINI_VERSION v0.6.0 - ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini - RUN chmod +x /usr/bin/tini - ENTRYPOINT ["/usr/bin/tini", "--"] - - EXPOSE 8888 - CMD ["jupyter", "server", "--port=8888", "--no-browser", "--ip=0.0.0.0"] diff --git a/server/docs/source/operators/security.rst b/server/docs/source/operators/security.rst deleted file mode 100644 index 87148cb..0000000 --- a/server/docs/source/operators/security.rst +++ /dev/null @@ -1,376 +0,0 @@ -.. _server_security: - -Security in the Jupyter Server -============================== - -Since access to the Jupyter Server means access to running arbitrary code, -it is important to restrict access to the server. -For this reason, Jupyter Server uses a token-based authentication that is **on by default**. - -.. note:: - - If you enable a password for your server, - token authentication is not enabled by default. - -When token authentication is enabled, the server uses a token to authenticate requests. -This token can be provided to login to the server in three ways: - -- in the ``Authorization`` header, e.g.:: - - Authorization: token abcdef... - -- In a URL parameter, e.g.:: - - https://my-server/tree/?token=abcdef... - -- In the password field of the login form that will be shown to you if you are not logged in. - -When you start a Jupyter server with token authentication enabled (default), -a token is generated to use for authentication. -This token is logged to the terminal, so that you can copy/paste the URL into your browser:: - - [I 11:59:16.597 ServerApp] The Jupyter Server is running at: - http://localhost:8888/?token=c8de56fa4deed24899803e93c227592aef6538f93025fe01 - - -If the Jupyter server is going to open your browser automatically, -an *additional* token is generated for launching the browser. -This additional token can be used only once, -and is used to set a cookie for your browser once it connects. -After your browser has made its first request with this one-time-token, -the token is discarded and a cookie is set in your browser. - -At any later time, you can see the tokens and URLs for all of your running servers with :command:`jupyter server list`:: - - $ jupyter server list - Currently running servers: - http://localhost:8888/?token=abc... :: /home/you/notebooks - https://0.0.0.0:9999/?token=123... :: /tmp/public - http://localhost:8889/ :: /tmp/has-password - -For servers with token-authentication enabled, the URL in the above listing will include the token, -so you can copy and paste that URL into your browser to login. -If a server has no token (e.g. it has a password or has authentication disabled), -the URL will not include the token argument. -Once you have visited this URL, -a cookie will be set in your browser and you won't need to use the token again, -unless you switch browsers, clear your cookies, or start a Jupyter server on a new port. - -Alternatives to token authentication ------------------------------------- - -If a generated token doesn't work well for you, -you can set a password for your server. -:command:`jupyter server password` will prompt you for a password, -and store the hashed password in your :file:`jupyter_server_config.json`. - -.. versionadded:: 5.0 - - :command:`jupyter server password` command is added. - - -It is possible disable authentication altogether by setting the token and password to empty strings, -but this is **NOT RECOMMENDED**, unless authentication or access restrictions are handled at a different layer in your web application: - -.. sourcecode:: python - - c.ServerApp.token = '' - c.ServerApp.password = '' - -Authorization -------------- - -.. versionadded:: 2.0 - -Authorization in Jupyter Server serves to provide finer grained control of access to its -API resources. With authentication, requests are accepted if the current user is known by -the server. Thus it can restrain access to specific users, but there is no way to give allowed -users more or less permissions. Jupyter Server provides a thin and extensible authorization layer -which checks if the current user is authorized to make a specific request. - -This is done by calling a ``is_authorized(handler, user, action, resource)`` method before each -request handler. Each request is labeled as either a "read", "write", or "execute" ``action``: - -- "read" wraps all ``GET`` and ``HEAD`` requests. - In general, read permissions grants access to read but not modify anything about the given resource. -- "write" wraps all ``POST``, ``PUT``, ``PATCH``, and ``DELETE`` requests. - In general, write permissions grants access to modify the given resource. -- "execute" wraps all requests to ZMQ/Websocket channels (terminals and kernels). - Execute is a special permission that usually corresponds to arbitrary execution, - such as via a kernel or terminal. - These permissions should generally be considered sufficient to perform actions equivalent - to ~all other permissions via other means. - -The ``resource`` being accessed refers to the resource name in the Jupyter Server's API endpoints. -In most cases, this is matches the field after `/api/`. -For instance, values for ``resource`` in the endpoints provided by the base jupyter server package, -and the corresponding permissions: - -.. list-table:: - :header-rows: 1 - - * - resource - - read - - write - - execute - - endpoints - - * - *resource name* - - *what can you do with read permissions?* - - *what can you do with write permissions?* - - *what can you do with execute permissions, if anything?* - - ``/api/...`` *what endpoints are governed by this resource?* - - * - api - - read server status (last activity, number of kernels, etc.), OpenAPI specification - - - - - - ``/api/status``, ``/api/spec.yaml`` - * - csp - - - - report content-security-policy violations - - - - ``/api/security/csp-report`` - * - config - - read frontend configuration, such as for notebook extensions - - modify frontend configuration - - - - ``/api/config`` - * - contents - - read files - - modify files (create, modify, delete) - - - - ``/api/contents``, ``/view``, ``/files`` - * - kernels - - list kernels, get status of kernels - - start, stop, and restart kernels - - Connect to kernel websockets, send/recv kernel messages. - **This generally means arbitrary code execution, - and should usually be considered equivalent to having all other permissions.** - - ``/api/kernels`` - * - kernelspecs - - read, list information about available kernels - - - - - - ``/api/kernelspecs`` - * - nbconvert - - render notebooks to other formats via nbconvert. - **Note: depending on server-side configuration, - this *could* involve execution.** - - - - - - ``/api/nbconvert`` - * - server - - - - Shutdown the server - - - - ``/api/shutdown`` - * - sessions - - list current sessions (association of documents to kernels) - - create, modify, and delete existing sessions, - which includes starting, stopping, and deleting kernels. - - - - ``/api/sessions`` - * - terminals - - list running terminals and their last activity - - start new terminals, stop running terminals - - Connect to terminal websockets, execute code in a shell. - **This generally means arbitrary code execution, - and should usually be considered equivalent to having all other permissions.** - - ``/api/terminals`` - - -Extensions may define their own resources. -Extension resources should start with ``extension_name:`` to avoid namespace conflicts. - -If ``is_authorized(...)`` returns ``True``, the request is made; otherwise, a -``HTTPError(403)`` (403 means "Forbidden") error is raised, and the request is blocked. - -By default, authorization is turned off—i.e. ``is_authorized()`` always returns ``True`` and -all authenticated users are allowed to make all types of requests. To turn-on authorization, pass -a class that inherits from ``Authorizer`` to the ``ServerApp.authorizer_class`` -parameter, implementing a ``is_authorized()`` method with your desired authorization logic, as -follows: - -.. sourcecode:: python - - from jupyter_server.auth import Authorizer - - class MyAuthorizationManager(Authorizer): - """Class for authorizing access to resources in the Jupyter Server. - - All authorizers used in Jupyter Server should inherit from - AuthorizationManager and, at the very minimum, override and implement - an `is_authorized` method with the following signature. - - The `is_authorized` method is called by the `@authorized` decorator in - JupyterHandler. If it returns True, the incoming request to the server - is accepted; if it returns False, the server returns a 403 (Forbidden) error code. - """ - - def is_authorized(self, handler: JupyterHandler, user: Any, action: str, resource: str) -> bool: - """A method to determine if `user` is authorized to perform `action` - (read, write, or execute) on the `resource` type. - - Parameters - ------------ - user : usually a dict or string - A truthy model representing the authenticated user. - A username string by default, - but usually a dict when integrating with an auth provider. - - action : str - the category of action for the current request: read, write, or execute. - - resource : str - the type of resource (i.e. contents, kernels, files, etc.) the user is requesting. - - Returns True if user authorized to make request; otherwise, returns False. - """ - return True # implement your authorization logic here - -The ``is_authorized()`` method will automatically be called whenever a handler is decorated with -``@authorized`` (from ``jupyter_server.auth``), similarly to the -``@authenticated`` decorator for authorization (from ``tornado.web``). - -Security in notebook documents -============================== - -As Jupyter Server become more popular for sharing and collaboration, -the potential for malicious people to attempt to exploit the notebook -for their nefarious purposes increases. IPython 2.0 introduced a -security model to prevent execution of untrusted code without explicit -user input. - -The problem ------------ - -The whole point of Jupyter is arbitrary code execution. We have no -desire to limit what can be done with a notebook, which would negatively -impact its utility. - -Unlike other programs, a Jupyter notebook document includes output. -Unlike other documents, that output exists in a context that can execute -code (via Javascript). - -The security problem we need to solve is that no code should execute -just because a user has **opened** a notebook that **they did not -write**. Like any other program, once a user decides to execute code in -a notebook, it is considered trusted, and should be allowed to do -anything. - -Our security model ------------------- - -- Untrusted HTML is always sanitized -- Untrusted Javascript is never executed -- HTML and Javascript in Markdown cells are never trusted -- **Outputs** generated by the user are trusted -- Any other HTML or Javascript (in Markdown cells, output generated by - others) is never trusted -- The central question of trust is "Did the current user do this?" - -The details of trust --------------------- - -When a notebook is executed and saved, a signature is computed from a -digest of the notebook's contents plus a secret key. This is stored in a -database, writable only by the current user. By default, this is located at:: - - ~/.local/share/jupyter/nbsignatures.db # Linux - ~/Library/Jupyter/nbsignatures.db # OS X - %APPDATA%/jupyter/nbsignatures.db # Windows - -Each signature represents a series of outputs which were produced by code the -current user executed, and are therefore trusted. - -When you open a notebook, the server computes its signature, and checks if it's -in the database. If a match is found, HTML and Javascript -output in the notebook will be trusted at load, otherwise it will be -untrusted. - -Any output generated during an interactive session is trusted. - -Updating trust -************** - -A notebook's trust is updated when the notebook is saved. If there are -any untrusted outputs still in the notebook, the notebook will not be -trusted, and no signature will be stored. If all untrusted outputs have -been removed (either via ``Clear Output`` or re-execution), then the -notebook will become trusted. - -While trust is updated per output, this is only for the duration of a -single session. A newly loaded notebook file is either trusted or not in its -entirety. - -Explicit trust -************** - -Sometimes re-executing a notebook to generate trusted output is not an -option, either because dependencies are unavailable, or it would take a -long time. Users can explicitly trust a notebook in two ways: - -- At the command-line, with:: - - jupyter trust /path/to/notebook.ipynb - -- After loading the untrusted notebook, with ``File / Trust Notebook`` - -These two methods simply load the notebook, compute a new signature, and add -that signature to the user's database. - -Reporting security issues -------------------------- - -If you find a security vulnerability in Jupyter, either a failure of the -code to properly implement the model described here, or a failure of the -model itself, please report it to security@ipython.org. - -If you prefer to encrypt your security reports, -you can use :download:`this PGP public key `. - -Affected use cases ------------------- - -Some use cases that work in Jupyter 1.0 became less convenient in -2.0 as a result of the security changes. We do our best to minimize -these annoyances, but security is always at odds with convenience. - -Javascript and CSS in Markdown cells -************************************ - -While never officially supported, it had become common practice to put -hidden Javascript or CSS styling in Markdown cells, so that they would -not be visible on the page. Since Markdown cells are now sanitized (by -`Google Caja `__), all Javascript -(including click event handlers, etc.) and CSS will be stripped. - -We plan to provide a mechanism for notebook themes, but in the meantime -styling the notebook can only be done via either ``custom.css`` or CSS -in HTML output. The latter only have an effect if the notebook is -trusted, because otherwise the output will be sanitized just like -Markdown. - -Collaboration -************* - -When collaborating on a notebook, people probably want to see the -outputs produced by their colleagues' most recent executions. Since each -collaborator's key will differ, this will result in each share starting -in an untrusted state. There are three basic approaches to this: - -- re-run notebooks when you get them (not always viable) -- explicitly trust notebooks via ``jupyter trust`` or the notebook menu - (annoying, but easy) -- share a notebook signatures database, and use configuration dedicated to the - collaboration while working on the project. - -To share a signatures database among users, you can configure: - -.. code-block:: python - - c.NotebookNotary.data_dir = "/path/to/signature_dir" - -to specify a non-default path to the SQLite database (of notebook hashes, -essentially). diff --git a/server/docs/source/other/faq.rst b/server/docs/source/other/faq.rst deleted file mode 100644 index db9e263..0000000 --- a/server/docs/source/other/faq.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _faq: - - -Frequently asked questions -========================== - -Here is a list of questions we think you might have. This list will always be growing, so please feel free to add your question+anwer to this page! |:rocket:| - - -Can I configure multiple extensions at once? --------------------------------------------- - -Checkout our "Operator" docs on how to :ref:`configure extensions `. |:closed_book:| diff --git a/server/docs/source/other/full-config.rst b/server/docs/source/other/full-config.rst deleted file mode 100644 index 55d708a..0000000 --- a/server/docs/source/other/full-config.rst +++ /dev/null @@ -1,1390 +0,0 @@ -.. _other-full-config: - - -Config file and command line options -==================================== - -The Jupyter Server can be run with a variety of command line arguments. -A list of available options can be found below in the :ref:`options section -`. - -Defaults for these options can also be set by creating a file named -``jupyter_server_config.py`` in your Jupyter folder. The Jupyter -folder is in your home directory, ``~/.jupyter``. - -To create a ``jupyter_server_config.py`` file, with all the defaults -commented out, you can use the following command line:: - - $ jupyter server --generate-config - - -.. _options: - -Options -------- - -This list of options can be generated by running the following and hitting -enter:: - - $ jupyter server --help-all - - - - -Application.log_datefmt : Unicode - Default: ``'%Y-%m-%d %H:%M:%S'`` - - The date format used by logging formatters for %(asctime)s - -Application.log_format : Unicode - Default: ``'[%(name)s]%(highlevel)s %(message)s'`` - - The Logging format template - -Application.log_level : any of ``0``|``10``|``20``|``30``|``40``|``50``|``'DEBUG'``|``'INFO'``|``'WARN'``|``'ERROR'``|``'CRITICAL'`` - Default: ``30`` - - Set the log level by value or name. - -Application.show_config : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout - -Application.show_config_json : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout (as JSON) - -JupyterApp.answer_yes : Bool - Default: ``False`` - - Answer yes to any prompts. - -JupyterApp.config_file : Unicode - Default: ``''`` - - Full path of a config file. - -JupyterApp.config_file_name : Unicode - Default: ``''`` - - Specify a config file to load. - -JupyterApp.generate_config : Bool - Default: ``False`` - - Generate default config file. - -JupyterApp.log_datefmt : Unicode - Default: ``'%Y-%m-%d %H:%M:%S'`` - - The date format used by logging formatters for %(asctime)s - -JupyterApp.log_format : Unicode - Default: ``'[%(name)s]%(highlevel)s %(message)s'`` - - The Logging format template - -JupyterApp.log_level : any of ``0``|``10``|``20``|``30``|``40``|``50``|``'DEBUG'``|``'INFO'``|``'WARN'``|``'ERROR'``|``'CRITICAL'`` - Default: ``30`` - - Set the log level by value or name. - -JupyterApp.show_config : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout - -JupyterApp.show_config_json : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout (as JSON) - -ServerApp.allow_credentials : Bool - Default: ``False`` - - Set the Access-Control-Allow-Credentials: true header - -ServerApp.allow_origin : Unicode - Default: ``''`` - - Set the Access-Control-Allow-Origin header - - Use '*' to allow any origin to access your server. - - Takes precedence over allow_origin_pat. - - -ServerApp.allow_origin_pat : Unicode - Default: ``''`` - - Use a regular expression for the Access-Control-Allow-Origin header - - Requests from an origin matching the expression will get replies with: - - Access-Control-Allow-Origin: origin - - where `origin` is the origin of the request. - - Ignored if allow_origin is set. - - -ServerApp.allow_password_change : Bool - Default: ``True`` - - Allow password to be changed at login for the Jupyter server. - - While logging in with a token, the Jupyter server UI will give the opportunity to - the user to enter a new password at the same time that will replace - the token login mechanism. - - This can be set to false to prevent changing password from the UI/API. - - -ServerApp.allow_remote_access : Bool - Default: ``False`` - - Allow requests where the Host header doesn't point to a local server - - By default, requests get a 403 forbidden response if the 'Host' header - shows that the browser thinks it's on a non-local domain. - Setting this option to True disables this check. - - This protects against 'DNS rebinding' attacks, where a remote web server - serves you a page and then changes its DNS to send later requests to a - local IP, bypassing same-origin checks. - - Local IP addresses (such as 127.0.0.1 and ::1) are allowed as local, - along with hostnames configured in local_hostnames. - - -ServerApp.allow_root : Bool - Default: ``False`` - - Whether to allow the user to run the server as root. - -ServerApp.answer_yes : Bool - Default: ``False`` - - Answer yes to any prompts. - -ServerApp.base_url : Unicode - Default: ``'/'`` - - The base URL for the Jupyter server. - - Leading and trailing slashes can be omitted, - and will automatically be added. - - -ServerApp.browser : Unicode - Default: ``''`` - - Specify what command to use to invoke a web - browser when starting the server. If not specified, the - default browser will be determined by the `webbrowser` - standard library module, which allows setting of the - BROWSER environment variable to override it. - - -ServerApp.certfile : Unicode - Default: ``''`` - - The full path to an SSL/TLS certificate file. - -ServerApp.client_ca : Unicode - Default: ``''`` - - The full path to a certificate authority certificate for SSL/TLS client authentication. - -ServerApp.config_file : Unicode - Default: ``''`` - - Full path of a config file. - -ServerApp.config_file_name : Unicode - Default: ``''`` - - Specify a config file to load. - -ServerApp.config_manager_class : Type - Default: ``'jupyter_server.services.config.manager.ConfigManager'`` - - The config manager class to use - -ServerApp.contents_manager_class : Type - Default: ``'jupyter_server.services.contents.largefilemanager.LargeFileM...`` - - The content manager class to use. - -ServerApp.cookie_options : Dict - Default: ``{}`` - - Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details. - -ServerApp.cookie_secret : Bytes - Default: ``b''`` - - The random bytes used to secure cookies. - By default this is a new random number every time you start the server. - Set it to a value in a config file to enable logins to persist across server sessions. - - Note: Cookie secrets should be kept private, do not share config files with - cookie_secret stored in plaintext (you can read the value from a file). - - -ServerApp.cookie_secret_file : Unicode - Default: ``''`` - - The file where the cookie secret is stored. - -ServerApp.custom_display_url : Unicode - Default: ``''`` - - Override URL shown to users. - - Replace actual URL, including protocol, address, port and base URL, - with the given value when displaying URL to the users. Do not change - the actual connection URL. If authentication token is enabled, the - token is added to the custom URL automatically. - - This option is intended to be used when the URL to display to the user - cannot be determined reliably by the Jupyter server (proxified - or containerized setups for example). - -ServerApp.default_url : Unicode - Default: ``'/'`` - - The default URL to redirect to from `/` - -ServerApp.disable_check_xsrf : Bool - Default: ``False`` - - Disable cross-site-request-forgery protection - - Jupyter notebook 4.3.1 introduces protection from cross-site request forgeries, - requiring API requests to either: - - - originate from pages served by this server (validated with XSRF cookie and token), or - - authenticate with a token - - Some anonymous compute resources still desire the ability to run code, - completely without authentication. - These services can disable all authentication and security checks, - with the full knowledge of what that implies. - - -ServerApp.extra_services : List - Default: ``[]`` - - handlers that should be loaded at higher priority than the default services - -ServerApp.extra_static_paths : List - Default: ``[]`` - - Extra paths to search for serving static files. - - This allows adding javascript/css to be available from the Jupyter server machine, - or overriding individual files in the IPython - -ServerApp.extra_template_paths : List - Default: ``[]`` - - Extra paths to search for serving jinja templates. - - Can be used to override templates from jupyter_server.templates. - -ServerApp.file_to_run : Unicode - Default: ``''`` - - No description - -ServerApp.generate_config : Bool - Default: ``False`` - - Generate default config file. - -ServerApp.get_secure_cookie_kwargs : Dict - Default: ``{}`` - - Extra keyword arguments to pass to `get_secure_cookie`. See tornado's get_secure_cookie docs for details. - -ServerApp.iopub_data_rate_limit : Float - Default: ``1000000`` - - (bytes/sec) - Maximum rate at which stream output can be sent on iopub before they are - limited. - -ServerApp.iopub_msg_rate_limit : Float - Default: ``1000`` - - (msgs/sec) - Maximum rate at which messages can be sent on iopub before they are - limited. - -ServerApp.ip : Unicode - Default: ``'localhost'`` - - The IP address the Jupyter server will listen on. - -ServerApp.jinja_environment_options : Dict - Default: ``{}`` - - Supply extra arguments that will be passed to Jinja environment. - -ServerApp.jinja_template_vars : Dict - Default: ``{}`` - - Extra variables to supply to jinja templates when rendering. - -ServerApp.jpserver_extensions : Dict - Default: ``{}`` - - Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order. - -ServerApp.kernel_manager_class : Type - Default: ``'jupyter_server.services.kernels.kernelmanager.MappingKernelM...`` - - The kernel manager class to use. - -ServerApp.kernel_spec_manager_class : Type - Default: ``'jupyter_client.kernelspec.KernelSpecManager'`` - - - The kernel spec manager class to use. Should be a subclass - of `jupyter_client.kernelspec.KernelSpecManager`. - - The Api of KernelSpecManager is provisional and might change - without warning between this version of Jupyter and the next stable one. - - -ServerApp.keyfile : Unicode - Default: ``''`` - - The full path to a private key file for usage with SSL/TLS. - -ServerApp.local_hostnames : List - Default: ``['localhost']`` - - Hostnames to allow as local when allow_remote_access is False. - - Local IP addresses (such as 127.0.0.1 and ::1) are automatically accepted - as local as well. - - -ServerApp.log_datefmt : Unicode - Default: ``'%Y-%m-%d %H:%M:%S'`` - - The date format used by logging formatters for %(asctime)s - -ServerApp.log_format : Unicode - Default: ``'[%(name)s]%(highlevel)s %(message)s'`` - - The Logging format template - -ServerApp.log_level : any of ``0``|``10``|``20``|``30``|``40``|``50``|``'DEBUG'``|``'INFO'``|``'WARN'``|``'ERROR'``|``'CRITICAL'`` - Default: ``30`` - - Set the log level by value or name. - -ServerApp.login_handler_class : Type - Default: ``'jupyter_server.auth.login.LoginHandler'`` - - The login handler class to use. - -ServerApp.logout_handler_class : Type - Default: ``'jupyter_server.auth.logout.LogoutHandler'`` - - The logout handler class to use. - -ServerApp.max_body_size : Int - Default: ``536870912`` - - - Sets the maximum allowed size of the client request body, specified in - the Content-Length request header field. If the size in a request - exceeds the configured value, a malformed HTTP message is returned to - the client. - - Note: max_body_size is applied even in streaming mode. - - -ServerApp.max_buffer_size : Int - Default: ``536870912`` - - - Gets or sets the maximum amount of memory, in bytes, that is allocated - for use by the buffer manager. - - -ServerApp.notebook_dir : Unicode - Default: ``''`` - - DEPRECATED, use root_dir. - -ServerApp.open_browser : Bool - Default: ``False`` - - Whether to open in a browser after starting. - The specific browser used is platform dependent and - determined by the python standard library `webbrowser` - module, unless it is overridden using the --browser - (ServerApp.browser) configuration option. - - -ServerApp.password : Unicode - Default: ``''`` - - Hashed password to use for web authentication. - - To generate, type in a python/IPython shell: - - from jupyter_server.auth import passwd; passwd() - - The string should be of the form type:salt:hashed-password. - - -ServerApp.password_required : Bool - Default: ``False`` - - Forces users to use a password for the Jupyter server. - This is useful in a multi user environment, for instance when - everybody in the LAN can access each other's machine through ssh. - - In such a case, serving on localhost is not secure since - any user can connect to the Jupyter server via ssh. - - - -ServerApp.port : Int - Default: ``8888`` - - The port the Jupyter server will listen on. - -ServerApp.port_retries : Int - Default: ``50`` - - The number of additional ports to try if the specified port is not available. - -ServerApp.pylab : Unicode - Default: ``'disabled'`` - - - DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib. - - -ServerApp.quit_button : Bool - Default: ``True`` - - If True, display controls to shut down the Jupyter server, such as menu items or buttons. - -ServerApp.rate_limit_window : Float - Default: ``3`` - - (sec) Time window used to - check the message and data rate limits. - -ServerApp.reraise_server_extension_failures : Bool - Default: ``False`` - - Reraise exceptions encountered loading server extensions? - -ServerApp.root_dir : Unicode - Default: ``''`` - - The directory to use for notebooks and kernels. - -ServerApp.session_manager_class : Type - Default: ``'jupyter_server.services.sessions.sessionmanager.SessionManager'`` - - The session manager class to use. - -ServerApp.show_config : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout - -ServerApp.show_config_json : Bool - Default: ``False`` - - Instead of starting the Application, dump configuration to stdout (as JSON) - -ServerApp.shutdown_no_activity_timeout : Int - Default: ``0`` - - Shut down the server after N seconds with no kernels or terminals running and no activity. This can be used together with culling idle kernels (MappingKernelManager.cull_idle_timeout) to shutdown the Jupyter server when it's not in use. This is not precisely timed: it may shut down up to a minute later. 0 (the default) disables this automatic shutdown. - -ServerApp.ssl_options : Dict - Default: ``{}`` - - Supply SSL options for the tornado HTTPServer. - See the tornado docs for details. - -ServerApp.terminado_settings : Dict - Default: ``{}`` - - Supply overrides for terminado. Currently only supports "shell_command". - -ServerApp.terminals_enabled : Bool - Default: ``True`` - - Set to False to disable terminals. - - This does *not* make the server more secure by itself. - Anything the user can in a terminal, they can also do in a notebook. - - Terminals may also be automatically disabled if the terminado package - is not available. - - -ServerApp.token : Unicode - Default: ``''`` - - Token used for authenticating first-time connections to the server. - - When no password is enabled, - the default is to generate a new, random token. - - Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED. - - -ServerApp.tornado_settings : Dict - Default: ``{}`` - - Supply overrides for the tornado.web.Application that the Jupyter server uses. - -ServerApp.trust_xheaders : Bool - Default: ``False`` - - Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL - -ServerApp.webbrowser_open_new : Int - Default: ``2`` - - Specify where to open the server on startup. This is the - `new` argument passed to the standard library method `webbrowser.open`. - The behaviour is not guaranteed, but depends on browser support. Valid - values are: - - - 2 opens a new tab, - - 1 opens a new window, - - 0 opens in an existing window. - - See the `webbrowser.open` documentation for details. - - -ServerApp.websocket_compression_options : Any - Default: ``None`` - - - Set the tornado compression options for websocket connections. - - This value will be returned from :meth:`WebSocketHandler.get_compression_options`. - None (default) will disable compression. - A dict (even an empty one) will enable compression. - - See the tornado docs for WebSocketHandler.get_compression_options for details. - - -ServerApp.websocket_url : Unicode - Default: ``''`` - - The base URL for websockets, - if it differs from the HTTP server (hint: it almost certainly doesn't). - - Should be in the form of an HTTP origin: ws[s]://hostname[:port] - - -ConnectionFileMixin.connection_file : Unicode - Default: ``''`` - - JSON file in which to store connection info [default: kernel-.json] - - This file will contain the IP, ports, and authentication key needed to connect - clients to this kernel. By default, this file will be created in the security dir - of the current profile, but can be specified by absolute path. - - -ConnectionFileMixin.control_port : Int - Default: ``0`` - - set the control (ROUTER) port [default: random] - -ConnectionFileMixin.hb_port : Int - Default: ``0`` - - set the heartbeat port [default: random] - -ConnectionFileMixin.iopub_port : Int - Default: ``0`` - - set the iopub (PUB) port [default: random] - -ConnectionFileMixin.ip : Unicode - Default: ``''`` - - Set the kernel's IP address [default localhost]. - If the IP address is something other than localhost, then - Consoles on other machines will be able to connect - to the Kernel, so be careful! - -ConnectionFileMixin.shell_port : Int - Default: ``0`` - - set the shell (ROUTER) port [default: random] - -ConnectionFileMixin.stdin_port : Int - Default: ``0`` - - set the stdin (ROUTER) port [default: random] - -ConnectionFileMixin.transport : any of ``'tcp'``|``'ipc'`` (case-insensitive) - Default: ``'tcp'`` - - No description - -KernelManager.autorestart : Bool - Default: ``True`` - - Should we autorestart the kernel if it dies. - -KernelManager.connection_file : Unicode - Default: ``''`` - - JSON file in which to store connection info [default: kernel-.json] - - This file will contain the IP, ports, and authentication key needed to connect - clients to this kernel. By default, this file will be created in the security dir - of the current profile, but can be specified by absolute path. - - -KernelManager.control_port : Int - Default: ``0`` - - set the control (ROUTER) port [default: random] - -KernelManager.hb_port : Int - Default: ``0`` - - set the heartbeat port [default: random] - -KernelManager.iopub_port : Int - Default: ``0`` - - set the iopub (PUB) port [default: random] - -KernelManager.ip : Unicode - Default: ``''`` - - Set the kernel's IP address [default localhost]. - If the IP address is something other than localhost, then - Consoles on other machines will be able to connect - to the Kernel, so be careful! - -KernelManager.kernel_cmd : List - Default: ``[]`` - - DEPRECATED: Use kernel_name instead. - - The Popen Command to launch the kernel. - Override this if you have a custom kernel. - If kernel_cmd is specified in a configuration file, - Jupyter does not pass any arguments to the kernel, - because it cannot make any assumptions about the - arguments that the kernel understands. In particular, - this means that the kernel does not receive the - option --debug if it given on the Jupyter command line. - - -KernelManager.shell_port : Int - Default: ``0`` - - set the shell (ROUTER) port [default: random] - -KernelManager.shutdown_wait_time : Float - Default: ``5.0`` - - Time to wait for a kernel to terminate before killing it, in seconds. - -KernelManager.stdin_port : Int - Default: ``0`` - - set the stdin (ROUTER) port [default: random] - -KernelManager.transport : any of ``'tcp'``|``'ipc'`` (case-insensitive) - Default: ``'tcp'`` - - No description - -Session.buffer_threshold : Int - Default: ``1024`` - - Threshold (in bytes) beyond which an object's buffer should be extracted to avoid pickling. - -Session.check_pid : Bool - Default: ``True`` - - Whether to check PID to protect against calls after fork. - - This check can be disabled if fork-safety is handled elsewhere. - - -Session.copy_threshold : Int - Default: ``65536`` - - Threshold (in bytes) beyond which a buffer should be sent without copying. - -Session.debug : Bool - Default: ``False`` - - Debug output in the Session - -Session.digest_history_size : Int - Default: ``65536`` - - The maximum number of digests to remember. - - The digest history will be culled when it exceeds this value. - - -Session.item_threshold : Int - Default: ``64`` - - The maximum number of items for a container to be introspected for custom serialization. - Containers larger than this are pickled outright. - - -Session.key : CBytes - Default: ``b''`` - - execution key, for signing messages. - -Session.keyfile : Unicode - Default: ``''`` - - path to file containing execution key. - -Session.metadata : Dict - Default: ``{}`` - - Metadata dictionary, which serves as the default top-level metadata dict for each message. - -Session.packer : DottedObjectName - Default: ``'json'`` - - The name of the packer for serializing messages. - Should be one of 'json', 'pickle', or an import name - for a custom callable serializer. - -Session.session : CUnicode - Default: ``''`` - - The UUID identifying this session. - -Session.signature_scheme : Unicode - Default: ``'hmac-sha256'`` - - The digest scheme used to construct the message signatures. - Must have the form 'hmac-HASH'. - -Session.unpacker : DottedObjectName - Default: ``'json'`` - - The name of the unpacker for unserializing messages. - Only used with custom functions for `packer`. - -Session.username : Unicode - Default: ``'username'`` - - Username for the Session. Default is your system username. - -MultiKernelManager.default_kernel_name : Unicode - Default: ``'python3'`` - - The name of the default kernel to start - -MultiKernelManager.kernel_manager_class : DottedObjectName - Default: ``'jupyter_client.ioloop.IOLoopKernelManager'`` - - The kernel manager class. This is configurable to allow - subclassing of the KernelManager for customized behavior. - - -MultiKernelManager.shared_context : Bool - Default: ``True`` - - Share a single zmq.Context to talk to all my kernels - -MappingKernelManager.allow_tracebacks : Bool - Default: ``True`` - - Whether to send tracebacks to clients on exceptions. - -MappingKernelManager.allowed_message_types : List - Default: ``[]`` - - White list of allowed kernel message types. - When the list is empty, all message types are allowed. - - -MappingKernelManager.buffer_offline_messages : Bool - Default: ``True`` - - Whether messages from kernels whose frontends have disconnected should be buffered in-memory. - - When True (default), messages are buffered and replayed on reconnect, - avoiding lost messages due to interrupted connectivity. - - Disable if long-running kernels will produce too much output while - no frontends are connected. - - -MappingKernelManager.cull_busy : Bool - Default: ``False`` - - Whether to consider culling kernels which are busy. - Only effective if cull_idle_timeout > 0. - -MappingKernelManager.cull_connected : Bool - Default: ``False`` - - Whether to consider culling kernels which have one or more connections. - Only effective if cull_idle_timeout > 0. - -MappingKernelManager.cull_idle_timeout : Int - Default: ``0`` - - Timeout (in seconds) after which a kernel is considered idle and ready to be culled. - Values of 0 or lower disable culling. Very short timeouts may result in kernels being culled - for users with poor network connections. - -MappingKernelManager.cull_interval : Int - Default: ``300`` - - The interval (in seconds) on which to check for idle kernels exceeding the cull timeout value. - -MappingKernelManager.default_kernel_name : Unicode - Default: ``'python3'`` - - The name of the default kernel to start - -MappingKernelManager.kernel_info_timeout : Float - Default: ``60`` - - Timeout for giving up on a kernel (in seconds). - - On starting and restarting kernels, we check whether the - kernel is running and responsive by sending kernel_info_requests. - This sets the timeout in seconds for how long the kernel can take - before being presumed dead. - This affects the MappingKernelManager (which handles kernel restarts) - and the ZMQChannelsHandler (which handles the startup). - - -MappingKernelManager.kernel_manager_class : DottedObjectName - Default: ``'jupyter_client.ioloop.IOLoopKernelManager'`` - - The kernel manager class. This is configurable to allow - subclassing of the KernelManager for customized behavior. - - -MappingKernelManager.root_dir : Unicode - Default: ``''`` - - No description - -MappingKernelManager.shared_context : Bool - Default: ``True`` - - Share a single zmq.Context to talk to all my kernels - -MappingKernelManager.traceback_replacement_message : Unicode - Default: ``'An exception occurred at runtime, which is not shown due to ...`` - - Message to print when allow_tracebacks is False, and an exception occurs - -KernelSpecManager.ensure_native_kernel : Bool - Default: ``True`` - - If there is no Python kernelspec registered and the IPython - kernel is available, ensure it is added to the spec list. - - -KernelSpecManager.kernel_spec_class : Type - Default: ``'jupyter_client.kernelspec.KernelSpec'`` - - The kernel spec class. This is configurable to allow - subclassing of the KernelSpecManager for customized behavior. - - -KernelSpecManager.whitelist : Set - Default: ``set()`` - - Whitelist of allowed kernel names. - - By default, all installed kernels are allowed. - - -ContentsManager.allow_hidden : Bool - Default: ``False`` - - Allow access to hidden files - -ContentsManager.checkpoints : Instance - Default: ``None`` - - No description - -ContentsManager.checkpoints_class : Type - Default: ``'jupyter_server.services.contents.checkpoints.Checkpoints'`` - - No description - -ContentsManager.checkpoints_kwargs : Dict - Default: ``{}`` - - No description - -ContentsManager.files_handler_class : Type - Default: ``'jupyter_server.files.handlers.FilesHandler'`` - - handler class to use when serving raw file requests. - - Default is a fallback that talks to the ContentsManager API, - which may be inefficient, especially for large files. - - Local files-based ContentsManagers can use a StaticFileHandler subclass, - which will be much more efficient. - - Access to these files should be Authenticated. - - -ContentsManager.files_handler_params : Dict - Default: ``{}`` - - Extra parameters to pass to files_handler_class. - - For example, StaticFileHandlers generally expect a `path` argument - specifying the root directory from which to serve files. - - -ContentsManager.hide_globs : List - Default: ``['__pycache__', '*.pyc', '*.pyo', '.DS_Store', '*.so', '*.dyl...`` - - - Glob patterns to hide in file and directory listings. - - -ContentsManager.pre_save_hook : Any - Default: ``None`` - - Python callable or importstring thereof - - To be called on a contents model prior to save. - - This can be used to process the structure, - such as removing notebook outputs or other side effects that - should not be saved. - - It will be called as (all arguments passed by keyword):: - - hook(path=path, model=model, contents_manager=self) - - - model: the model to be saved. Includes file contents. - Modifying this dict will affect the file that is stored. - - path: the API path of the save destination - - contents_manager: this ContentsManager instance - - -ContentsManager.root_dir : Unicode - Default: ``'/'`` - - No description - -ContentsManager.untitled_directory : Unicode - Default: ``'Untitled Folder'`` - - The base name used when creating untitled directories. - -ContentsManager.untitled_file : Unicode - Default: ``'untitled'`` - - The base name used when creating untitled files. - -ContentsManager.untitled_notebook : Unicode - Default: ``'Untitled'`` - - The base name used when creating untitled notebooks. - -FileManagerMixin.use_atomic_writing : Bool - Default: ``True`` - - By default notebooks are saved on disk on a temporary file and then if succefully written, it replaces the old ones. - This procedure, namely 'atomic_writing', causes some bugs on file system whitout operation order enforcement (like some networked fs). - If set to False, the new notebook is written directly on the old one which could fail (eg: full filesystem or quota ) - -FileContentsManager.allow_hidden : Bool - Default: ``False`` - - Allow access to hidden files - -FileContentsManager.checkpoints : Instance - Default: ``None`` - - No description - -FileContentsManager.checkpoints_class : Type - Default: ``'jupyter_server.services.contents.checkpoints.Checkpoints'`` - - No description - -FileContentsManager.checkpoints_kwargs : Dict - Default: ``{}`` - - No description - -FileContentsManager.delete_to_trash : Bool - Default: ``True`` - - If True (default), deleting files will send them to the - platform's trash/recycle bin, where they can be recovered. If False, - deleting files really deletes them. - -FileContentsManager.files_handler_class : Type - Default: ``'jupyter_server.files.handlers.FilesHandler'`` - - handler class to use when serving raw file requests. - - Default is a fallback that talks to the ContentsManager API, - which may be inefficient, especially for large files. - - Local files-based ContentsManagers can use a StaticFileHandler subclass, - which will be much more efficient. - - Access to these files should be Authenticated. - - -FileContentsManager.files_handler_params : Dict - Default: ``{}`` - - Extra parameters to pass to files_handler_class. - - For example, StaticFileHandlers generally expect a `path` argument - specifying the root directory from which to serve files. - - -FileContentsManager.hide_globs : List - Default: ``['__pycache__', '*.pyc', '*.pyo', '.DS_Store', '*.so', '*.dyl...`` - - - Glob patterns to hide in file and directory listings. - - -FileContentsManager.post_save_hook : Any - Default: ``None`` - - Python callable or importstring thereof - - to be called on the path of a file just saved. - - This can be used to process the file on disk, - such as converting the notebook to a script or HTML via nbconvert. - - It will be called as (all arguments passed by keyword):: - - hook(os_path=os_path, model=model, contents_manager=instance) - - - path: the filesystem path to the file just written - - model: the model representing the file - - contents_manager: this ContentsManager instance - - -FileContentsManager.pre_save_hook : Any - Default: ``None`` - - Python callable or importstring thereof - - To be called on a contents model prior to save. - - This can be used to process the structure, - such as removing notebook outputs or other side effects that - should not be saved. - - It will be called as (all arguments passed by keyword):: - - hook(path=path, model=model, contents_manager=self) - - - model: the model to be saved. Includes file contents. - Modifying this dict will affect the file that is stored. - - path: the API path of the save destination - - contents_manager: this ContentsManager instance - - -FileContentsManager.root_dir : Unicode - Default: ``''`` - - No description - -FileContentsManager.untitled_directory : Unicode - Default: ``'Untitled Folder'`` - - The base name used when creating untitled directories. - -FileContentsManager.untitled_file : Unicode - Default: ``'untitled'`` - - The base name used when creating untitled files. - -FileContentsManager.untitled_notebook : Unicode - Default: ``'Untitled'`` - - The base name used when creating untitled notebooks. - -FileContentsManager.use_atomic_writing : Bool - Default: ``True`` - - By default notebooks are saved on disk on a temporary file and then if succefully written, it replaces the old ones. - This procedure, namely 'atomic_writing', causes some bugs on file system whitout operation order enforcement (like some networked fs). - If set to False, the new notebook is written directly on the old one which could fail (eg: full filesystem or quota ) - -NotebookNotary.algorithm : any of ``'blake2s'``|``'sha512'``|``'md5'``|``'sha3_512'``|``'sha3_224'``|``'blake2b'``|``'sha384'``|``'sha1'``|``'sha3_256'``|``'sha256'``|``'sha224'``|``'sha3_384'`` - Default: ``'sha256'`` - - The hashing algorithm used to sign notebooks. - -NotebookNotary.db_file : Unicode - Default: ``''`` - - The sqlite file in which to store notebook signatures. - By default, this will be in your Jupyter data directory. - You can set it to ':memory:' to disable sqlite writing to the filesystem. - - -NotebookNotary.secret : Bytes - Default: ``b''`` - - The secret key with which notebooks are signed. - -NotebookNotary.secret_file : Unicode - Default: ``''`` - - The file where the secret key is stored. - -NotebookNotary.store_factory : Callable - Default: ``traitlets.Undefined`` - - A callable returning the storage backend for notebook signatures. - The default uses an SQLite database. - -GatewayMappingKernelManager.allow_tracebacks : Bool - Default: ``True`` - - Whether to send tracebacks to clients on exceptions. - -GatewayMappingKernelManager.allowed_message_types : List - Default: ``[]`` - - White list of allowed kernel message types. - When the list is empty, all message types are allowed. - - -GatewayMappingKernelManager.buffer_offline_messages : Bool - Default: ``True`` - - Whether messages from kernels whose frontends have disconnected should be buffered in-memory. - - When True (default), messages are buffered and replayed on reconnect, - avoiding lost messages due to interrupted connectivity. - - Disable if long-running kernels will produce too much output while - no frontends are connected. - - -GatewayMappingKernelManager.cull_busy : Bool - Default: ``False`` - - Whether to consider culling kernels which are busy. - Only effective if cull_idle_timeout > 0. - -GatewayMappingKernelManager.cull_connected : Bool - Default: ``False`` - - Whether to consider culling kernels which have one or more connections. - Only effective if cull_idle_timeout > 0. - -GatewayMappingKernelManager.cull_idle_timeout : Int - Default: ``0`` - - Timeout (in seconds) after which a kernel is considered idle and ready to be culled. - Values of 0 or lower disable culling. Very short timeouts may result in kernels being culled - for users with poor network connections. - -GatewayMappingKernelManager.cull_interval : Int - Default: ``300`` - - The interval (in seconds) on which to check for idle kernels exceeding the cull timeout value. - -GatewayMappingKernelManager.default_kernel_name : Unicode - Default: ``'python3'`` - - The name of the default kernel to start - -GatewayMappingKernelManager.kernel_info_timeout : Float - Default: ``60`` - - Timeout for giving up on a kernel (in seconds). - - On starting and restarting kernels, we check whether the - kernel is running and responsive by sending kernel_info_requests. - This sets the timeout in seconds for how long the kernel can take - before being presumed dead. - This affects the MappingKernelManager (which handles kernel restarts) - and the ZMQChannelsHandler (which handles the startup). - - -GatewayMappingKernelManager.kernel_manager_class : DottedObjectName - Default: ``'jupyter_client.ioloop.IOLoopKernelManager'`` - - The kernel manager class. This is configurable to allow - subclassing of the KernelManager for customized behavior. - - -GatewayMappingKernelManager.root_dir : Unicode - Default: ``''`` - - No description - -GatewayMappingKernelManager.shared_context : Bool - Default: ``True`` - - Share a single zmq.Context to talk to all my kernels - -GatewayMappingKernelManager.traceback_replacement_message : Unicode - Default: ``'An exception occurred at runtime, which is not shown due to ...`` - - Message to print when allow_tracebacks is False, and an exception occurs - -GatewayKernelSpecManager.ensure_native_kernel : Bool - Default: ``True`` - - If there is no Python kernelspec registered and the IPython - kernel is available, ensure it is added to the spec list. - - -GatewayKernelSpecManager.kernel_spec_class : Type - Default: ``'jupyter_client.kernelspec.KernelSpec'`` - - The kernel spec class. This is configurable to allow - subclassing of the KernelSpecManager for customized behavior. - - -GatewayKernelSpecManager.whitelist : Set - Default: ``set()`` - - Whitelist of allowed kernel names. - - By default, all installed kernels are allowed. - - - - -GatewayClient.auth_token : Unicode - Default: ``None`` - - The authorization token used in the HTTP headers. (JUPYTER_GATEWAY_AUTH_TOKEN env var) - - -GatewayClient.ca_certs : Unicode - Default: ``None`` - - The filename of CA certificates or None to use defaults. (JUPYTER_GATEWAY_CA_CERTS env var) - - -GatewayClient.client_cert : Unicode - Default: ``None`` - - The filename for client SSL certificate, if any. (JUPYTER_GATEWAY_CLIENT_CERT env var) - - -GatewayClient.client_key : Unicode - Default: ``None`` - - The filename for client SSL key, if any. (JUPYTER_GATEWAY_CLIENT_KEY env var) - - -GatewayClient.connect_timeout : Float - Default: ``60.0`` - - The time allowed for HTTP connection establishment with the Gateway server. - (JUPYTER_GATEWAY_CONNECT_TIMEOUT env var) - -GatewayClient.env_whitelist : Unicode - Default: ``''`` - - A comma-separated list of environment variable names that will be included, along with - their values, in the kernel startup request. The corresponding `env_whitelist` configuration - value must also be set on the Gateway server - since that configuration value indicates which - environmental values to make available to the kernel. (JUPYTER_GATEWAY_ENV_WHITELIST env var) - -GatewayClient.headers : Unicode - Default: ``'{}'`` - - Additional HTTP headers to pass on the request. This value will be converted to a dict. - (JUPYTER_GATEWAY_HEADERS env var) - - -GatewayClient.http_pwd : Unicode - Default: ``None`` - - The password for HTTP authentication. (JUPYTER_GATEWAY_HTTP_PWD env var) - - -GatewayClient.http_user : Unicode - Default: ``None`` - - The username for HTTP authentication. (JUPYTER_GATEWAY_HTTP_USER env var) - - -GatewayClient.kernels_endpoint : Unicode - Default: ``'/api/kernels'`` - - The gateway API endpoint for accessing kernel resources (JUPYTER_GATEWAY_KERNELS_ENDPOINT env var) - -GatewayClient.kernelspecs_endpoint : Unicode - Default: ``'/api/kernelspecs'`` - - The gateway API endpoint for accessing kernelspecs (JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT env var) - -GatewayClient.kernelspecs_resource_endpoint : Unicode - Default: ``'/kernelspecs'`` - - The gateway endpoint for accessing kernelspecs resources - (JUPYTER_GATEWAY_KERNELSPECS_RESOURCE_ENDPOINT env var) - -GatewayClient.request_timeout : Float - Default: ``60.0`` - - The time allowed for HTTP request completion. (JUPYTER_GATEWAY_REQUEST_TIMEOUT env var) - -GatewayClient.url : Unicode - Default: ``None`` - - The url of the Kernel or Enterprise Gateway server where - kernel specifications are defined and kernel management takes place. - If defined, this Notebook server acts as a proxy for all kernel - management and kernel specification retrieval. (JUPYTER_GATEWAY_URL env var) - - -GatewayClient.validate_cert : Bool - Default: ``True`` - - For HTTPS requests, determines if server's certificate should be validated or not. - (JUPYTER_GATEWAY_VALIDATE_CERT env var) - -GatewayClient.ws_url : Unicode - Default: ``None`` - - The websocket url of the Kernel or Enterprise Gateway server. If not provided, this value - will correspond to the value of the Gateway url with 'ws' in place of 'http'. (JUPYTER_GATEWAY_WS_URL env var) diff --git a/server/docs/source/other/index.rst b/server/docs/source/other/index.rst deleted file mode 100644 index e3ddd8d..0000000 --- a/server/docs/source/other/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Other helpful documentation ---------------------------- - -.. toctree:: - :maxdepth: 1 - - links - faq - full-config - changelog diff --git a/server/docs/source/other/links.rst b/server/docs/source/other/links.rst deleted file mode 100644 index 935ddc5..0000000 --- a/server/docs/source/other/links.rst +++ /dev/null @@ -1,9 +0,0 @@ -List of helpful links -===================== - -* :ref:`Frequently Asked Questions ` -* `Jupyter Server Github Repo `_ -* `JupyterLab Github Repo `_ -* `Jupyter Notebook Github Repo `_ -* `Jupyterhub Github Repo `_ -* `Jupyter Zoom Channel `_ diff --git a/server/docs/source/users/configuration.rst b/server/docs/source/users/configuration.rst deleted file mode 100644 index b6ede5b..0000000 --- a/server/docs/source/users/configuration.rst +++ /dev/null @@ -1,68 +0,0 @@ -.. _user-configuring-a-jupyter-server: - -Configuring a Jupyter Server -============================ - -Using a Jupyter config file ---------------------------- - -By default, Jupyter Server looks for server-specific configuration in a ``jupyter_server_config`` file located on a Jupyter path. To list the paths where Jupyter Server will look, run: - -.. code-block:: console - - $ jupyter --paths - - config: - /Users/username/.jupyter - /usr/local/etc/jupyter - /etc/jupyter - data: - /Users/username/Library/Jupyter - /usr/local/share/jupyter - /usr/share/jupyter - runtime: - /Users/username/Library/Jupyter/runtime - - -The paths under ``config`` are listed in order of precedence. If the same trait is listed in multiple places, it will be set to the value from the file will highest precendence. - - -Jupyter Server uses IPython's traitlets system for configuration. Traits can be listed in a Python or JSON config file. You can quickly create a ``jupyter_server_config.py`` file in the ``.jupyter`` directory, with all the defaults commented out, use the following command: - -.. code-block:: console - - $ jupyter server --generate-config - -In Python files, these traits will have the prefix ``c.ServerApp``. For example, your configuration file could look like: - -.. code-block:: python - - # inside a jupyter_server_config.py file. - - c.ServerApp.port = 9999 - -The same configuration in JSON, looks like: - -.. code-block:: json - - { - "ServerApp": { - "port": 9999 - } - } - - -Using the CLI -------------- - -Alternatively, you can configure Jupyter Server when launching from the command line using CLI args. Prefix each argument with ``--ServerApp`` like so: - -.. code-block:: console - - $ jupyter server --ServerApp.port=9999 - - -Full configuration list ------------------------ - -See the full list of configuration options for the server :ref:`here `. diff --git a/server/docs/source/users/help.rst b/server/docs/source/users/help.rst deleted file mode 100644 index b290e1b..0000000 --- a/server/docs/source/users/help.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _user-getting-help: - -Getting Help -============ - -If you run into any issues or bugs, please open an `issue on Github `_. - -We'd also love to have you come by our :ref:`Team Meetings `. diff --git a/server/docs/source/users/index.rst b/server/docs/source/users/index.rst deleted file mode 100644 index 3f0bab7..0000000 --- a/server/docs/source/users/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -Documentation for Users -======================= - -The Jupyter Server is a highly technical piece of the Jupyter Stack, so users probably won't import or install this library directly. These pages are to meant to help you in case you run into issues or bugs. - - -.. toctree:: - :caption: Users - :maxdepth: 1 - :name: users - - installation - configuration - launching - help diff --git a/server/docs/source/users/installation.rst b/server/docs/source/users/installation.rst deleted file mode 100644 index 3bc0e37..0000000 --- a/server/docs/source/users/installation.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _user-installation: - -Installation -============ - -Most Jupyter users will **never need to install Jupyter Server manually**. Jupyter Web applications will include the (correct version) of Jupyter Server as a dependency. It's best to let those applications handle installation, because they may require a specific version of Jupyter Server. - -If you decide to install manually, run: - -.. code-block:: bash - - pip install jupyter_server - - -You upgrade or downgrade to a specific version of Jupyter Server by adding an operator to the command above: - -.. code-block:: bash - - pip install jupyter_server==1.0 diff --git a/server/docs/source/users/launching.rst b/server/docs/source/users/launching.rst deleted file mode 100644 index 1338b74..0000000 --- a/server/docs/source/users/launching.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _user-launching-a-bare-jupyter-server: - -Launching a bare Jupyter Server -=============================== - -Most of the time, you won't need to start the Jupyter Server directly. Jupyter Web Applications (like Jupyter Notebook, Jupyterlab, Voila, etc.) come with their own entry points that start a server automatically. - -Sometimes, though, it can be useful to start Jupyter Server directly when you want to run multiple Jupyter Web applications at the same time. For more details, see the :ref:`Managing multiple extensions ` page. If these extensions are enabled, you can simple run the following: - -.. code-block:: bash - - > jupyter server - - [I 2020-03-20 15:48:20.903 ServerApp] Serving notebooks from local directory: /Users/username/home - [I 2020-03-20 15:48:20.903 ServerApp] Jupyter Server 1.0.0 is running at: - [I 2020-03-20 15:48:20.903 ServerApp] http://localhost:8888/?token=<...> - [I 2020-03-20 15:48:20.903 ServerApp] or http://127.0.0.1:8888/?token=<...> - [I 2020-03-20 15:48:20.903 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). - [I 2020-03-20 15:48:20.903 ServerApp] Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at https://jupyter.org/community.html. - [C 2020-03-20 15:48:20.907 ServerApp] - - To access the server, open this file in a browser: - file:///Users/username/jpserver-###-open.html - Or copy and paste one of these URLs: - http://localhost:8888/?token=<...> - or http://127.0.0.1:8888/?token=<...> diff --git a/server/examples/authorization/README.md b/server/examples/authorization/README.md deleted file mode 100644 index 28fe0df..0000000 --- a/server/examples/authorization/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Authorization in a simple Jupyter Notebook Server - -This folder contains the following examples: - -1. a "read-only" Jupyter Notebook Server -2. a read/write Server without the ability to execute code on kernels. -3. a "temporary notebook server", i.e. read and execute notebooks but cannot save/write files. - -## How does it work? - -To add a custom authorization system to the Jupyter Server, you will need to write your own `Authorizer` subclass and pass it to Jupyter's configuration system (i.e. by file or CLI). - -The examples below demonstrate some basic implementations of an `Authorizer`. - -```python -from jupyter_server.auth import Authorizer - - -class MyCustomAuthorizer(Authorizer): - """Custom authorization manager.""" - - # Define my own method here for handling authorization. - # The argument signature must have `self`, `handler`, `user`, `action`, and `resource`. - def is_authorized(self, handler, user, action, resource): - """My override for handling authorization in Jupyter services.""" - - # Add logic here to check if user is allowed. - # For example, here is an example of a read-only server - if action != "read": - return False - - return True - -# Pass this custom class to Jupyter Server -c.ServerApp.authorizer_class = MyCustomAuthorizer -``` - -In the `jupyter_nbclassic_readonly_config.py` - -## Try it out! - -### Read-only example - -1. Install nbclassic using `pip`. - - pip install nbclassic - -2. Navigate to the jupyter_authorized_server `examples/` folder. - -3. Launch nbclassic and load `jupyter_nbclassic_readonly_config.py`: - - jupyter nbclassic --config=jupyter_nbclassic_readonly_config.py - -4. Try creating a notebook, running a notebook in a cell, etc. You should see a `403: Forbidden` error. - -### Read+Write example - -1. Install nbclassic using `pip`. - - pip install nbclassic - -2. Navigate to the jupyter_authorized_server `examples/` folder. - -3. Launch nbclassic and load `jupyter_nbclassic_rw_config.py`: - - jupyter nbclassic --config=jupyter_nbclassic_rw_config.py - -4. Try running a cell in a notebook. You should see a `403: Forbidden` error. - -### Temporary notebook server example - -This configuration allows everything except saving files. - -1. Install nbclassic using `pip`. - - pip install nbclassic - -2. Navigate to the jupyter_authorized_server `examples/` folder. - -3. Launch nbclassic and load `jupyter_temporary_config.py`: - - jupyter nbclassic --config=jupyter_temporary_config.py - -4. Edit a notebook, run a cell, etc. Everything works fine. Then try to save your changes... you should see a `403: Forbidden` error. diff --git a/server/examples/authorization/jupyter_nbclassic_readonly_config.py b/server/examples/authorization/jupyter_nbclassic_readonly_config.py deleted file mode 100644 index 292644c..0000000 --- a/server/examples/authorization/jupyter_nbclassic_readonly_config.py +++ /dev/null @@ -1,14 +0,0 @@ -from jupyter_server.auth import Authorizer - - -class ReadOnly(Authorizer): - """Authorizer that makes Jupyter Server a read-only server.""" - - def is_authorized(self, handler, user, action, resource): - """Only allows `read` operations.""" - if action != "read": - return False - return True - - -c.ServerApp.authorizer_class = ReadOnly diff --git a/server/examples/authorization/jupyter_nbclassic_rw_config.py b/server/examples/authorization/jupyter_nbclassic_rw_config.py deleted file mode 100644 index 261efcf..0000000 --- a/server/examples/authorization/jupyter_nbclassic_rw_config.py +++ /dev/null @@ -1,14 +0,0 @@ -from jupyter_server.auth import Authorizer - - -class ReadWriteOnly(Authorizer): - """Authorizer class that makes Jupyter Server a read/write-only server.""" - - def is_authorized(self, handler, user, action, resource): - """Only allows `read` and `write` operations.""" - if action not in {"read", "write"}: - return False - return True - - -c.ServerApp.authorizer_class = ReadWriteOnly diff --git a/server/examples/authorization/jupyter_temporary_config.py b/server/examples/authorization/jupyter_temporary_config.py deleted file mode 100644 index e1bd2fb..0000000 --- a/server/examples/authorization/jupyter_temporary_config.py +++ /dev/null @@ -1,14 +0,0 @@ -from jupyter_server.auth import Authorizer - - -class TemporaryServerPersonality(Authorizer): - """Authorizer that prevents modifying files via the contents service""" - - def is_authorized(self, handler, user, action, resource): - """Allow everything but write on contents""" - if action == "write" and resource == "contents": - return False - return True - - -c.ServerApp.authorizer_class = TemporaryServerPersonality diff --git a/server/examples/simple/README.md b/server/examples/simple/README.md deleted file mode 100644 index f41eb5b..0000000 --- a/server/examples/simple/README.md +++ /dev/null @@ -1,204 +0,0 @@ -# Jupyter Server Simple Extension Example - -This folder contains example of simple extensions on top of Jupyter Server and review configuration aspects. - -## Install - -You need `python3` to build and run the server extensions. - -```bash -# Clone, create a conda env and install from source. -git clone https://github.com/jupyter/jupyter_server && \ - cd examples/simple && \ - conda create -y -n jupyter-server-example python=3.7 && \ - conda activate jupyter-server-example && \ - pip install -e .[test] -``` - -**OPTIONAL** If you want to build the Typescript code, you need [npm](https://www.npmjs.com) on your local environement. Compiled javascript is provided as artifact in this repository, so this Typescript build step is optional. The Typescript source and configuration have been taken from https://github.com/markellekelly/jupyter-server-example. - -```bash -npm install && \ - npm run build -``` - -## No Extension - -Ensure Jupyter Server is starting without any extension enabled. - -```bash -# Run this command from a shell. -jupyter server -``` - -Browse the default home page, it should show a white page in your browser with the following content: `A Jupyter Server is running.` - -```bash -# Jupyter Server default Home Page. -open http://localhost:8888 -``` - -## Extension 1 - -```bash -# Start the jupyter server activating simple_ext1 extension. -jupyter server --ServerApp.jpserver_extensions="{'simple_ext1': True}" -``` - -Now you can render `Extension 1` Server content in your browser. - -```bash -# Home page as defined by default_url = '/default'. -open http://localhost:8888/simple_ext1/default -# HTML static page. -open http://localhost:8888/static/simple_ext1/home.html -open http://localhost:8888/static/simple_ext1/test.html -# Content from Handlers. -open http://localhost:8888/simple_ext1/params/test?var1=foo -# Content from Template. -open http://localhost:8888/simple_ext1/template1/test -# Content from Template with Typescript. -open http://localhost:8888/simple_ext1/typescript -# Error content. -open http://localhost:8888/simple_ext1/nope -# Redirect. -open http://localhost:8888/simple_ext1/redirect -# Favicon static content. -open http://localhost:8888/static/simple_ext1/favicon.ico -``` - -You can also start the server extension with python modules. - -```bash -python -m simple_ext1 -``` - -To live reload the server as you change the extension, you can also enable [the `debug` mode for Tornado](https://www.tornadoweb.org/en/stable/guide/running.html#debug-mode-and-automatic-reloading): - -```bash -jupyter server --ServerApp.jpserver_extensions="{'simple_ext1': True}" --ServerApp.tornado_settings="{'debug': True}" -``` - -## Extension 1 and Extension 2 - -The following command starts both the `simple_ext1` and `simple_ext2` extensions. - -```bash -# Start the jupyter server, it will load both simple_ext1 and simple_ext2 based on the provided trait. -jupyter server --ServerApp.jpserver_extensions="{'simple_ext1': True, 'simple_ext2': True}" -``` - -Check that the previous `Extension 1` content is still available ant that you can also render `Extension 2` Server content in your browser. - -```bash -# HTML static page. -open http://localhost:8888/static/simple_ext2/test.html -# Content from Handlers. -open http://localhost:8888/simple_ext2/params/test?var1=foo -``` - -## Work with Entrypoints - -Optionally, you can copy `simple_ext1.json` and `simple_ext2.json` configuration to your env `etc` folder and start only Extension 1, which will also start Extension 2. - -```bash -pip uninstall -y jupyter_server_example && \ - python setup.py install && \ - cp -r ./etc $(dirname $(which jupyter))/.. -``` - -```bash -# Start the jupyter server extension simple_ext1, it will also load simple_ext2 because of load_other_extensions = True.. -# When you invoke with the entrypoint, the default url will be opened in your browser. -jupyter simple-ext1 -``` - -## Configuration - -Stop any running server (with `CTRL+C`) and start with additional configuration on the command line. - -The provided settings via CLI will override the configuration that reside in the files (`jupyter_server_example1_config.py`...) - -```bash -jupyter simple-ext1 --SimpleApp1.configA="ConfigA from command line" -``` - -Check the log, it should return on startup print the Config object. - -The content of the Config is based on the trait you have defined via the `CLI` and in the `jupyter_server_example1_config.py`. - -``` -[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from file', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}} -[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from file', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}} -[SimpleApp2] WARNING | Config option `configD` not recognized by `SimpleApp2`. Did you mean one of: `configA, configB, configC`? -[SimpleApp2] Config {'SimpleApp2': {'configD': 'ConfigD from file'}} -[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from command line', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}} -``` - -## Only Extension 2 - -Now stop agin the server and start with only `Extension 2`. - -```bash -# Start the jupyter server extension simple_ext2, it will NOT load simple_ext1 because of load_other_extensions = False. -jupyter simple-ext2 -``` - -Try with the above links to check that only Extension 2 is responding (Extension 1 URLs should give you an 404 error). - -## Extension 11 extends Extension 1 - -`Extension 11` extends `Extension 1` and brings a few more configs. - -```bash -# TODO `--generate-config` returns an exception `"The ExtensionApp has not ServerApp "` -jupyter simple-ext11 --generate-config && vi ~/.jupyter/jupyter_config.py`. -``` - -The generated configuration should contains the following. - -```bash -# TODO -``` - -The `hello`, `ignore_js` and `simple11_dir` are traits defined on the SimpleApp11 class. - -It also implements additional flags and aliases for these traits. - -- The `--hello` flag will log on startup `Hello Simple11 - You have provided the --hello flag or defined a c.SimpleApp1.hello == True` -- The `ignore_js` flag -- The `--simple11-dir` alias will set `SimpleExt11.simple11_dir` settings - -Stop any running server and then start the simple-ext11. - -```bash -jupyter simple-ext11 --hello --simple11-dir any_folder -# You can also launch with a module -python -m simple_ext11 --hello -# TODO FIX the following command, simple11 does not work launching with jpserver_extensions parameter. -jupyter server --ServerApp.jpserver_extensions="{'simple_ext11': True}" --hello --simple11-dir any_folder -``` - -Ensure the following URLs respond correctly. - -```bash -# Jupyter Server Home Page. -open http://localhost:8888/ -# TODO Fix Default URL, it does not show on startup. -# Home page as defined by default_url = '/default'. -open http://localhost:8888/simple_ext11/default -# HTML static page. -open http://localhost:8888/static/simple_ext11/test.html -# Content from Handlers. -open http://localhost:8888/simple_ext11/params/test?var1=foo -# Content from Template. -open http://localhost:8888/simple_ext11/template1/test -# Content from Template with Typescript. -open http://localhost:8888/simple_ext11/typescript -# Error content. -open http://localhost:8888/simple_ext11/nope -# Redirect. -open http://localhost:8888/simple_ext11/redirect -# Favicon static content. -open http://localhost:8888/static/simple_ext11/favicon.ico -``` diff --git a/server/examples/simple/conftest.py b/server/examples/simple/conftest.py deleted file mode 100644 index 366de33..0000000 --- a/server/examples/simple/conftest.py +++ /dev/null @@ -1 +0,0 @@ -from jupyter_server.conftest import * # noqa diff --git a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext1.json b/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext1.json deleted file mode 100644 index fd4b771..0000000 --- a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ServerApp": { - "jpserver_extensions": { - "simple_ext1": true - } - } -} diff --git a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext11.json b/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext11.json deleted file mode 100644 index 6857ee2..0000000 --- a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext11.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ServerApp": { - "jpserver_extensions": { - "simple_ext11": true - } - } -} diff --git a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext2.json b/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext2.json deleted file mode 100644 index 287a167..0000000 --- a/server/examples/simple/etc/jupyter/jupyter_server_config.d/simple_ext2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ServerApp": { - "jpserver_extensions": { - "simple_ext2": true - } - } -} diff --git a/server/examples/simple/jupyter_server_config.py b/server/examples/simple/jupyter_server_config.py deleted file mode 100644 index b994a71..0000000 --- a/server/examples/simple/jupyter_server_config.py +++ /dev/null @@ -1,6 +0,0 @@ -# Configuration file for jupyter-server extensions. -# ------------------------------------------------------------------------------ -# Application(SingletonConfigurable) configuration -# ------------------------------------------------------------------------------ -## The date format used by logging formatters for %(asctime)s -c.Application.log_datefmt = "%Y-%m-%d %H:%M:%S Simple_Extensions_Example" diff --git a/server/examples/simple/jupyter_simple_ext11_config.py b/server/examples/simple/jupyter_simple_ext11_config.py deleted file mode 100644 index d2baa13..0000000 --- a/server/examples/simple/jupyter_simple_ext11_config.py +++ /dev/null @@ -1 +0,0 @@ -c.SimpleApp11.ignore_js = True diff --git a/server/examples/simple/jupyter_simple_ext1_config.py b/server/examples/simple/jupyter_simple_ext1_config.py deleted file mode 100644 index f40b66a..0000000 --- a/server/examples/simple/jupyter_simple_ext1_config.py +++ /dev/null @@ -1,4 +0,0 @@ -c.SimpleApp1.configA = "ConfigA from file" -c.SimpleApp1.configB = "ConfigB from file" -c.SimpleApp1.configC = "ConfigC from file" -c.SimpleApp1.configD = "ConfigD from file" diff --git a/server/examples/simple/jupyter_simple_ext2_config.py b/server/examples/simple/jupyter_simple_ext2_config.py deleted file mode 100644 index f145cbb..0000000 --- a/server/examples/simple/jupyter_simple_ext2_config.py +++ /dev/null @@ -1 +0,0 @@ -c.SimpleApp2.configD = "ConfigD from file" diff --git a/server/examples/simple/package.json b/server/examples/simple/package.json deleted file mode 100644 index 37f76ba..0000000 --- a/server/examples/simple/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "jupyter-server-example", - "version": "0.0.1", - "private": true, - "scripts": { - "build": "tsc -p src && webpack", - "clean": "rimraf build", - "prepublishOnly": "npm run build" - }, - "dependencies": {}, - "devDependencies": { - "rifraf": "2.0.3", - "webpack": "~4.29.6", - "webpack-cli": "^3.3.0", - "whatwg-fetch": "~2.0.3", - "typescript": "3.6.4" - } -} diff --git a/server/examples/simple/pyproject.toml b/server/examples/simple/pyproject.toml deleted file mode 100644 index d4ff206..0000000 --- a/server/examples/simple/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -requires = ["jupyter_packaging~=0.5.0", "setuptools>=40.8.0", "wheel"] -build-backend = "setuptools.build_meta" diff --git a/server/examples/simple/pytest.ini b/server/examples/simple/pytest.ini deleted file mode 100644 index 31e2592..0000000 --- a/server/examples/simple/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -# Disable any upper exclusion. -norecursedirs = diff --git a/server/examples/simple/setup.py b/server/examples/simple/setup.py deleted file mode 100644 index bf9ee4a..0000000 --- a/server/examples/simple/setup.py +++ /dev/null @@ -1,58 +0,0 @@ -import os - -from jupyter_packaging import create_cmdclass -from setuptools import setup - - -VERSION = "0.0.1" - - -def get_data_files(): - """Get the data files for the package.""" - data_files = [ - ("etc/jupyter/jupyter_server_config.d", "etc/jupyter/jupyter_server_config.d/", "*.json"), - ] - - def add_data_files(path): - for (dirpath, dirnames, filenames) in os.walk(path): - if filenames: - paths = [(dirpath, dirpath, filename) for filename in filenames] - data_files.extend(paths) - - # Add all static and templates folders. - add_data_files("simple_ext1/static") - add_data_files("simple_ext1/templates") - add_data_files("simple_ext2/static") - add_data_files("simple_ext2/templates") - return data_files - - -cmdclass = create_cmdclass(data_files_spec=get_data_files()) - -setup_args = dict( - name="jupyter_server_example", - version=VERSION, - description="Jupyter Server Example", - long_description=open("README.md").read(), - python_requires=">=3.7", - install_requires=[ - "jupyter_server", - "jinja2", - ], - extras_require={ - "test": ["pytest"], - }, - include_package_data=True, - cmdclass=cmdclass, - entry_points={ - "console_scripts": [ - "jupyter-simple-ext1 = simple_ext1.application:main", - "jupyter-simple-ext11 = simple_ext11.application:main", - "jupyter-simple-ext2 = simple_ext2.application:main", - ] - }, -) - - -if __name__ == "__main__": - setup(**setup_args) diff --git a/server/examples/simple/simple_ext1/__init__.py b/server/examples/simple/simple_ext1/__init__.py deleted file mode 100644 index 7b0c65c..0000000 --- a/server/examples/simple/simple_ext1/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .application import SimpleApp1 - - -def _jupyter_server_extension_paths(): - return [{"module": "simple_ext1.application", "app": SimpleApp1}] diff --git a/server/examples/simple/simple_ext1/__main__.py b/server/examples/simple/simple_ext1/__main__.py deleted file mode 100644 index 317a0bd..0000000 --- a/server/examples/simple/simple_ext1/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .application import main - -if __name__ == "__main__": - main() diff --git a/server/examples/simple/simple_ext1/application.py b/server/examples/simple/simple_ext1/application.py deleted file mode 100644 index 91e734f..0000000 --- a/server/examples/simple/simple_ext1/application.py +++ /dev/null @@ -1,61 +0,0 @@ -import os - -from traitlets import Unicode - -from .handlers import DefaultHandler -from .handlers import ErrorHandler -from .handlers import ParameterHandler -from .handlers import RedirectHandler -from .handlers import TemplateHandler -from .handlers import TypescriptHandler -from jupyter_server.extension.application import ExtensionApp -from jupyter_server.extension.application import ExtensionAppJinjaMixin - -DEFAULT_STATIC_FILES_PATH = os.path.join(os.path.dirname(__file__), "static") -DEFAULT_TEMPLATE_FILES_PATH = os.path.join(os.path.dirname(__file__), "templates") - - -class SimpleApp1(ExtensionAppJinjaMixin, ExtensionApp): - - # The name of the extension. - name = "simple_ext1" - - # The url that your extension will serve its homepage. - extension_url = "/simple_ext1/default" - - # Should your extension expose other server extensions when launched directly? - load_other_extensions = True - - # Local path to static files directory. - static_paths = [DEFAULT_STATIC_FILES_PATH] - - # Local path to templates directory. - template_paths = [DEFAULT_TEMPLATE_FILES_PATH] - - configA = Unicode("", config=True, help="Config A example.") - - configB = Unicode("", config=True, help="Config B example.") - - configC = Unicode("", config=True, help="Config C example.") - - def initialize_handlers(self): - self.handlers.extend( - [ - (r"/{}/default".format(self.name), DefaultHandler), - (r"/{}/params/(.+)$".format(self.name), ParameterHandler), - (r"/{}/template1/(.*)$".format(self.name), TemplateHandler), - (r"/{}/redirect".format(self.name), RedirectHandler), - (r"/{}/typescript/?".format(self.name), TypescriptHandler), - (r"/{}/(.*)", ErrorHandler), - ] - ) - - def initialize_settings(self): - self.log.info("Config {}".format(self.config)) - - -# ----------------------------------------------------------------------------- -# Main entry point -# ----------------------------------------------------------------------------- - -main = launch_new_instance = SimpleApp1.launch_instance diff --git a/server/examples/simple/simple_ext1/handlers.py b/server/examples/simple/simple_ext1/handlers.py deleted file mode 100644 index 1f412e8..0000000 --- a/server/examples/simple/simple_ext1/handlers.py +++ /dev/null @@ -1,51 +0,0 @@ -from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin -from jupyter_server.extension.handler import ExtensionHandlerMixin -from jupyter_server.utils import url_escape - - -class DefaultHandler(ExtensionHandlerMixin, JupyterHandler): - def get(self): - # The name of the extension to which this handler is linked. - self.log.info("Extension Name in {} Default Handler: {}".format(self.name, self.name)) - # A method for getting the url to static files (prefixed with /static/). - self.log.info( - "Static URL for / in simple_ext1 Default Handler: {}".format(self.static_url(https://github.com/path=%22/")) - ) - self.write("

    Hello Simple 1 - I am the default...

    ") - self.write("Config in {} Default Handler: {}".format(self.name, self.config)) - - -class RedirectHandler(ExtensionHandlerMixin, JupyterHandler): - def get(self): - self.redirect("/static/{}/favicon.ico".format(self.name)) - - -class ParameterHandler(ExtensionHandlerMixin, JupyterHandler): - def get(self, matched_part=None, *args, **kwargs): - var1 = self.get_argument("var1", default=None) - components = [x for x in self.request.path.split("/") if x] - self.write("

    Hello Simple App 1 from Handler.

    ") - self.write("

    matched_part: {}

    ".format(url_escape(matched_part))) - self.write("

    var1: {}

    ".format(url_escape(var1))) - self.write("

    components: {}

    ".format(components)) - - -class BaseTemplateHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): - pass - - -class TypescriptHandler(BaseTemplateHandler): - def get(self): - self.write(self.render_template("typescript.html")) - - -class TemplateHandler(BaseTemplateHandler): - def get(self, path): - """Optionaly, you can print(self.get_template('simple1.html'))""" - self.write(self.render_template("simple1.html", path=path)) - - -class ErrorHandler(BaseTemplateHandler): - def get(self, path): - self.write(self.render_template("error.html", path=path)) diff --git a/server/examples/simple/simple_ext1/static/bundle.js b/server/examples/simple/simple_ext1/static/bundle.js deleted file mode 100644 index 9017d38..0000000 --- a/server/examples/simple/simple_ext1/static/bundle.js +++ /dev/null @@ -1,144 +0,0 @@ -/******/ (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; // define getter function for harmony exports - /******/ - /******/ /******/ __webpack_require__.d = function (exports, name, getter) { - /******/ if (!__webpack_require__.o(exports, name)) { - /******/ Object.defineProperty(exports, name, { - enumerable: true, - get: getter, - }); - /******/ - } - /******/ - }; // define __esModule on exports - /******/ - /******/ /******/ __webpack_require__.r = function (exports) { - /******/ if (typeof Symbol !== "undefined" && Symbol.toStringTag) { - /******/ Object.defineProperty(exports, Symbol.toStringTag, { - value: "Module", - }); - /******/ - } - /******/ Object.defineProperty(exports, "__esModule", { value: true }); - /******/ - }; // create a fake namespace object // mode & 1: value is a module id, require it // mode & 2: merge all properties of value into the ns // mode & 4: return value when already ns object // mode & 8|1: behave like require - /******/ - /******/ /******/ /******/ /******/ /******/ /******/ __webpack_require__.t = - function (value, mode) { - /******/ if (mode & 1) value = __webpack_require__(value); - /******/ if (mode & 8) return value; - /******/ if ( - mode & 4 && - typeof value === "object" && - value && - value.__esModule - ) - return value; - /******/ var ns = Object.create(null); - /******/ __webpack_require__.r(ns); - /******/ Object.defineProperty(ns, "default", { - enumerable: true, - value: value, - }); - /******/ if (mode & 2 && typeof value != "string") - for (var key in value) - __webpack_require__.d( - ns, - key, - function (key) { - return value[key]; - }.bind(null, key) - ); - /******/ return ns; - /******/ - }; // 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 = 0)); - /******/ -})( - /************************************************************************/ - /******/ { - /***/ "./simple_ext1/static/index.js": - /*!*************************************!*\ - !*** ./simple_ext1/static/index.js ***! - \*************************************/ - /*! no static exports found */ - /***/ function (module, exports) { - eval( - 'function main() {\n let div = document.getElementById("mydiv");\n div.innerText = "Hello from Typescript";\n}\nwindow.addEventListener(\'load\', main);\n\n\n//# sourceURL=webpack:///./simple_ext1/static/index.js?' - ); - - /***/ - }, - - /***/ 0: - /*!*******************************************!*\ - !*** multi ./simple_ext1/static/index.js ***! - \*******************************************/ - /*! no static exports found */ - /***/ function (module, exports, __webpack_require__) { - eval( - 'module.exports = __webpack_require__(/*! ./simple_ext1/static/index.js */"./simple_ext1/static/index.js");\n\n\n//# sourceURL=webpack:///multi_./simple_ext1/static/index.js?' - ); - - /***/ - }, - - /******/ - } -); diff --git a/server/examples/simple/simple_ext1/static/favicon.ico b/server/examples/simple/simple_ext1/static/favicon.ico deleted file mode 100644 index 2d1bcff..0000000 Binary files a/server/examples/simple/simple_ext1/static/favicon.ico and /dev/null differ diff --git a/server/examples/simple/simple_ext1/static/home.html b/server/examples/simple/simple_ext1/static/home.html deleted file mode 100644 index 27fffd9..0000000 --- a/server/examples/simple/simple_ext1/static/home.html +++ /dev/null @@ -1 +0,0 @@ -

    Welcome to Simple App 1 Home Page.

    diff --git a/server/examples/simple/simple_ext1/static/index.d.ts b/server/examples/simple/simple_ext1/static/index.d.ts deleted file mode 100644 index 1be3002..0000000 --- a/server/examples/simple/simple_ext1/static/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare function main(): void; diff --git a/server/examples/simple/simple_ext1/static/index.js b/server/examples/simple/simple_ext1/static/index.js deleted file mode 100644 index 4cc84b9..0000000 --- a/server/examples/simple/simple_ext1/static/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let div = document.getElementById("mydiv"); - div.innerText = "Hello from Typescript"; -} -window.addEventListener("load", main); diff --git a/server/examples/simple/simple_ext1/static/test.html b/server/examples/simple/simple_ext1/static/test.html deleted file mode 100644 index 8c0bb51..0000000 --- a/server/examples/simple/simple_ext1/static/test.html +++ /dev/null @@ -1 +0,0 @@ -

    Hello Simple App 1 from test HTML page.

    diff --git a/server/examples/simple/simple_ext1/templates/error.html b/server/examples/simple/simple_ext1/templates/error.html deleted file mode 100644 index 1379574..0000000 --- a/server/examples/simple/simple_ext1/templates/error.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "page.html" %} - -{% block site %} - -
    - {% block h1_error %} -

    Error Page

    -

    {{status_code}} : {{status_message}}

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

    {% trans %}The error was:{% endtrans %}

    -
    -
    {{message}}
    -
    - {% endif %} - {% endblock error_detail %} -
    - -{% endblock %} diff --git a/server/examples/simple/simple_ext1/templates/page.html b/server/examples/simple/simple_ext1/templates/page.html deleted file mode 100644 index cf01c9a..0000000 --- a/server/examples/simple/simple_ext1/templates/page.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - {% block title %}Jupyter Server 1{% endblock %} - {% block favicon %}{% endblock %} - - - {% block meta %} - {% endblock %} - - -
    - {% block site %} - {% endblock site %} -
    - {% block after_site %} - {% endblock after_site %} - - diff --git a/server/examples/simple/simple_ext1/templates/simple1.html b/server/examples/simple/simple_ext1/templates/simple1.html deleted file mode 100644 index 95d8403..0000000 --- a/server/examples/simple/simple_ext1/templates/simple1.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - -

    Hello Simple App 1 from Template.

    -

    Path: {{path}}

    - diff --git a/server/examples/simple/simple_ext1/templates/typescript.html b/server/examples/simple/simple_ext1/templates/typescript.html deleted file mode 100644 index e825cf3..0000000 --- a/server/examples/simple/simple_ext1/templates/typescript.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - -
    -

    Hello world!

    -
    - diff --git a/server/examples/simple/simple_ext11/__init__.py b/server/examples/simple/simple_ext11/__init__.py deleted file mode 100644 index abe0f73..0000000 --- a/server/examples/simple/simple_ext11/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .application import SimpleApp11 - - -def _jupyter_server_extension_paths(): - return [{"module": "simple_ext11.application", "app": SimpleApp11}] diff --git a/server/examples/simple/simple_ext11/__main__.py b/server/examples/simple/simple_ext11/__main__.py deleted file mode 100644 index 317a0bd..0000000 --- a/server/examples/simple/simple_ext11/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .application import main - -if __name__ == "__main__": - main() diff --git a/server/examples/simple/simple_ext11/application.py b/server/examples/simple/simple_ext11/application.py deleted file mode 100644 index 82411dd..0000000 --- a/server/examples/simple/simple_ext11/application.py +++ /dev/null @@ -1,75 +0,0 @@ -import os - -from simple_ext1.application import SimpleApp1 -from traitlets import Bool -from traitlets import observe -from traitlets import Unicode - -from jupyter_server.serverapp import aliases -from jupyter_server.serverapp import flags - -DEFAULT_STATIC_FILES_PATH = os.path.join(os.path.dirname(__file__), "./../simple_ext1/static") -DEFAULT_TEMPLATE_FILES_PATH = os.path.join(os.path.dirname(__file__), "./../simple_ext1/templates") - - -class SimpleApp11(SimpleApp1): - flags["hello"] = ({"SimpleApp11": {"hello": True}}, "Say hello on startup.") - aliases.update( - { - "simple11-dir": "SimpleApp11.simple11_dir", - } - ) - - # The name of the extension. - name = "simple_ext11" - - # Te url that your extension will serve its homepage. - extension_url = "/simple_ext11/default" - - # Local path to static files directory. - static_paths = [DEFAULT_STATIC_FILES_PATH] - - # Local path to templates directory. - template_paths = [DEFAULT_TEMPLATE_FILES_PATH] - - simple11_dir = Unicode("", config=True, help="Simple directory") - - hello = Bool( - False, - config=True, - help="Say hello", - ) - - ignore_js = Bool( - False, - config=True, - help="Ignore Javascript", - ) - - @observe("ignore_js") - def _update_ignore_js(self, change): - """TODO Does the observe work?""" - self.log.info("ignore_js has just changed: {}".format(change)) - - @property - def simple11_dir_formatted(self): - return "/" + self.simple11_dir - - def initialize_settings(self): - self.log.info("hello: {}".format(self.hello)) - if self.hello == True: - self.log.info( - "Hello Simple11: You have launched with --hello flag or defined 'c.SimpleApp1.hello == True' in your config file" - ) - self.log.info("ignore_js: {}".format(self.ignore_js)) - super().initialize_settings() - - def initialize_handlers(self): - super().initialize_handlers() - - -# ----------------------------------------------------------------------------- -# Main entry point -# ----------------------------------------------------------------------------- - -main = launch_new_instance = SimpleApp11.launch_instance diff --git a/server/examples/simple/simple_ext2/__init__.py b/server/examples/simple/simple_ext2/__init__.py deleted file mode 100644 index ffe7bc4..0000000 --- a/server/examples/simple/simple_ext2/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .application import SimpleApp2 - - -def _jupyter_server_extension_paths(): - return [ - {"module": "simple_ext2.application", "app": SimpleApp2}, - ] diff --git a/server/examples/simple/simple_ext2/__main__.py b/server/examples/simple/simple_ext2/__main__.py deleted file mode 100644 index 317a0bd..0000000 --- a/server/examples/simple/simple_ext2/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .application import main - -if __name__ == "__main__": - main() diff --git a/server/examples/simple/simple_ext2/application.py b/server/examples/simple/simple_ext2/application.py deleted file mode 100644 index fcda51d..0000000 --- a/server/examples/simple/simple_ext2/application.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - -from traitlets import Unicode - -from .handlers import ErrorHandler -from .handlers import IndexHandler -from .handlers import ParameterHandler -from .handlers import TemplateHandler -from jupyter_server.extension.application import ExtensionApp -from jupyter_server.extension.application import ExtensionAppJinjaMixin - -DEFAULT_STATIC_FILES_PATH = os.path.join(os.path.dirname(__file__), "static") -DEFAULT_TEMPLATE_FILES_PATH = os.path.join(os.path.dirname(__file__), "templates") - - -class SimpleApp2(ExtensionAppJinjaMixin, ExtensionApp): - - # The name of the extension. - name = "simple_ext2" - - # Te url that your extension will serve its homepage. - extension_url = "/simple_ext2" - - # Should your extension expose other server extensions when launched directly? - load_other_extensions = True - - # Local path to static files directory. - static_paths = [DEFAULT_STATIC_FILES_PATH] - - # Local path to templates directory. - template_paths = [DEFAULT_TEMPLATE_FILES_PATH] - - configD = Unicode("", config=True, help="Config D example.") - - def initialize_handlers(self): - self.handlers.extend( - [ - (r"/simple_ext2/params/(.+)$", ParameterHandler), - (r"/simple_ext2/template", TemplateHandler), - (r"/simple_ext2/?", IndexHandler), - (r"/simple_ext2/(.*)", ErrorHandler), - ] - ) - - def initialize_settings(self): - self.log.info("Config {}".format(self.config)) - - -# ----------------------------------------------------------------------------- -# Main entry point -# ----------------------------------------------------------------------------- - -main = launch_new_instance = SimpleApp2.launch_instance diff --git a/server/examples/simple/simple_ext2/handlers.py b/server/examples/simple/simple_ext2/handlers.py deleted file mode 100644 index 2e37fe8..0000000 --- a/server/examples/simple/simple_ext2/handlers.py +++ /dev/null @@ -1,34 +0,0 @@ -from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin -from jupyter_server.extension.handler import ExtensionHandlerMixin -from jupyter_server.utils import url_escape - - -class ParameterHandler(ExtensionHandlerMixin, JupyterHandler): - def get(self, matched_part=None, *args, **kwargs): - var1 = self.get_argument("var1", default=None) - components = [x for x in self.request.path.split("/") if x] - self.write("

    Hello Simple App 2 from Handler.

    ") - self.write("

    matched_part: {}

    ".format(url_escape(matched_part))) - self.write("

    var1: {}

    ".format(url_escape(var1))) - self.write("

    components: {}

    ".format(components)) - - -class BaseTemplateHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): - pass - - -class IndexHandler(BaseTemplateHandler): - def get(self): - self.write(self.render_template("index.html")) - - -class TemplateHandler(BaseTemplateHandler): - def get(self, path): - print(self.get_template("simple_ext2.html")) - self.write(self.render_template("simple_ext2.html", path=path)) - - -class ErrorHandler(BaseTemplateHandler): - def get(self, path): - self.write(self.render_template("error.html")) diff --git a/server/examples/simple/simple_ext2/static/favicon.ico b/server/examples/simple/simple_ext2/static/favicon.ico deleted file mode 100644 index 2d1bcff..0000000 Binary files a/server/examples/simple/simple_ext2/static/favicon.ico and /dev/null differ diff --git a/server/examples/simple/simple_ext2/static/test.html b/server/examples/simple/simple_ext2/static/test.html deleted file mode 100644 index 1ac418d..0000000 --- a/server/examples/simple/simple_ext2/static/test.html +++ /dev/null @@ -1 +0,0 @@ -

    Hello Simple App 2 from test HTML page.

    diff --git a/server/examples/simple/simple_ext2/templates/error.html b/server/examples/simple/simple_ext2/templates/error.html deleted file mode 100644 index 7426beb..0000000 --- a/server/examples/simple/simple_ext2/templates/error.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "page.html" %} - -{% block site %} - -
    - {% block h1_error %} -

    {{status_code}} : {{status_message}}

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

    {% trans %}The error was:{% endtrans %}

    -
    -
    {{message}}
    -
    - {% endif %} - {% endblock error_detail %} -
    - -{% endblock %} diff --git a/server/examples/simple/simple_ext2/templates/index.html b/server/examples/simple/simple_ext2/templates/index.html deleted file mode 100644 index a42a0ab..0000000 --- a/server/examples/simple/simple_ext2/templates/index.html +++ /dev/null @@ -1 +0,0 @@ -

    Hello Extension 2 from HTML Index Static Page

    diff --git a/server/examples/simple/simple_ext2/templates/page.html b/server/examples/simple/simple_ext2/templates/page.html deleted file mode 100644 index cf01c9a..0000000 --- a/server/examples/simple/simple_ext2/templates/page.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - {% block title %}Jupyter Server 1{% endblock %} - {% block favicon %}{% endblock %} - - - {% block meta %} - {% endblock %} - - -
    - {% block site %} - {% endblock site %} -
    - {% block after_site %} - {% endblock after_site %} - - diff --git a/server/examples/simple/simple_ext2/templates/simple_ext2.html b/server/examples/simple/simple_ext2/templates/simple_ext2.html deleted file mode 100644 index 0c7df48..0000000 --- a/server/examples/simple/simple_ext2/templates/simple_ext2.html +++ /dev/null @@ -1 +0,0 @@ -

    Hello Extension 2 from Simple HTML Static Page

    diff --git a/server/examples/simple/tests/test_handlers.py b/server/examples/simple/tests/test_handlers.py deleted file mode 100644 index 7c4cb69..0000000 --- a/server/examples/simple/tests/test_handlers.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest - - -@pytest.fixture -def jp_server_config(jp_template_dir): - return { - "ServerApp": {"jpserver_extensions": {"simple_ext1": True}}, - } - - -async def test_handler_default(jp_fetch): - r = await jp_fetch("https://github.com/simple_ext1/default", method="GET") - assert r.code == 200 - print(r.body.decode()) - assert r.body.decode().index("Hello Simple 1 - I am the default...") > -1 - - -async def test_handler_template(jp_fetch): - r = await jp_fetch("https://github.com/simple_ext1/template1/test", method="GET") - assert r.code == 200 diff --git a/server/examples/simple/webpack.config.js b/server/examples/simple/webpack.config.js deleted file mode 100644 index b242d09..0000000 --- a/server/examples/simple/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - entry: ['./simple_ext1/static/index.js'], - output: { - path: require('path').join(__dirname, 'simple_ext1', 'static'), - filename: 'bundle.js' - }, - mode: 'development' -}; diff --git a/server/jupyter_server/__init__.py b/server/jupyter_server/__init__.py deleted file mode 100644 index 3a6586a..0000000 --- a/server/jupyter_server/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -"""The Jupyter Server""" -import os -import subprocess -import sys - -DEFAULT_STATIC_FILES_PATH = os.path.join(os.path.dirname(__file__), "static") -DEFAULT_TEMPLATE_PATH_LIST = [ - os.path.dirname(__file__), - os.path.join(os.path.dirname(__file__), "templates"), -] - -DEFAULT_JUPYTER_SERVER_PORT = 8888 - -del os - -from ._version import version_info, __version__ # noqa - - -def _cleanup(): - pass - - -# patch subprocess on Windows for python<3.7 -# see https://bugs.python.org/issue37380 -# the fix for python3.7: https://github.com/python/cpython/pull/15706/files -if sys.platform == "win32": - if sys.version_info < (3, 7): - subprocess._cleanup = _cleanup - subprocess._active = None diff --git a/server/jupyter_server/__main__.py b/server/jupyter_server/__main__.py deleted file mode 100644 index 6ada4be..0000000 --- a/server/jupyter_server/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -if __name__ == "__main__": - from jupyter_server import serverapp as app - - app.launch_new_instance() diff --git a/server/jupyter_server/_sysinfo.py b/server/jupyter_server/_sysinfo.py deleted file mode 100644 index 6dbc9f7..0000000 --- a/server/jupyter_server/_sysinfo.py +++ /dev/null @@ -1,97 +0,0 @@ -# encoding: utf-8 -""" -Utilities for getting information about Jupyter and the system it's running in. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import platform -import subprocess -import sys - -from ipython_genutils import encoding - -import jupyter_server - - -def pkg_commit_hash(pkg_path): - """Get short form of commit hash given directory `pkg_path` - - We get the commit hash from git if it's a repo. - - If this fail, we return a not-found placeholder tuple - - Parameters - ---------- - pkg_path : str - directory containing package - only used for getting commit from active repo - - Returns - ------- - hash_from : str - Where we got the hash from - description - hash_str : str - short form of hash - """ - - # maybe we are in a repository, check for a .git folder - p = os.path - cur_path = None - par_path = pkg_path - while cur_path != par_path: - cur_path = par_path - if p.exists(p.join(cur_path, ".git")): - try: - proc = subprocess.Popen( - ["git", "rev-parse", "--short", "HEAD"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=pkg_path, - ) - repo_commit, _ = proc.communicate() - except OSError: - repo_commit = None - - if repo_commit: - return "repository", repo_commit.strip().decode("ascii") - else: - return "", "" - par_path = p.dirname(par_path) - - return "", "" - - -def pkg_info(pkg_path): - """Return dict describing the context of this package - - Parameters - ---------- - pkg_path : str - path containing __init__.py for package - - Returns - ------- - context : dict - with named parameters of interest - """ - src, hsh = pkg_commit_hash(pkg_path) - return dict( - jupyter_server_version=jupyter_server.__version__, - jupyter_server_path=pkg_path, - commit_source=src, - commit_hash=hsh, - sys_version=sys.version, - sys_executable=sys.executable, - sys_platform=sys.platform, - platform=platform.platform(), - os_name=os.name, - default_encoding=encoding.DEFAULT_ENCODING, - ) - - -def get_sys_info(): - """Return useful information about the system as a dict.""" - p = os.path - path = p.realpath(p.dirname(p.abspath(p.join(jupyter_server.__file__)))) - return pkg_info(path) diff --git a/server/jupyter_server/_tz.py b/server/jupyter_server/_tz.py deleted file mode 100644 index 4ea8cfc..0000000 --- a/server/jupyter_server/_tz.py +++ /dev/null @@ -1,49 +0,0 @@ -# encoding: utf-8 -""" -Timezone utilities - -Just UTC-awareness right now -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from datetime import datetime -from datetime import timedelta -from datetime import tzinfo - -# constant for zero offset -ZERO = timedelta(0) - - -class tzUTC(tzinfo): - """tzinfo object for UTC (zero offset)""" - - def utcoffset(self, d): - return ZERO - - def dst(self, d): - return ZERO - - -UTC = tzUTC() - - -def utc_aware(unaware): - """decorator for adding UTC tzinfo to datetime's utcfoo methods""" - - def utc_method(*args, **kwargs): - dt = unaware(*args, **kwargs) - return dt.replace(tzinfo=UTC) - - return utc_method - - -utcfromtimestamp = utc_aware(datetime.utcfromtimestamp) -utcnow = utc_aware(datetime.utcnow) - - -def isoformat(dt): - """Return iso-formatted timestamp - - Like .isoformat(), but uses Z for UTC instead of +00:00 - """ - return dt.isoformat().replace("+00:00", "Z") diff --git a/server/jupyter_server/_version.py b/server/jupyter_server/_version.py deleted file mode 100644 index b45a4eb..0000000 --- a/server/jupyter_server/_version.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -store the current version info of the server. - -""" -version_info = (1, 14, 0, ".dev", "0") -__version__ = ".".join(map(str, version_info[:3])) + "".join(version_info[3:]) diff --git a/server/jupyter_server/auth/__init__.py b/server/jupyter_server/auth/__init__.py deleted file mode 100644 index 54477ff..0000000 --- a/server/jupyter_server/auth/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .authorizer import * # noqa -from .decorator import authorized # noqa -from .security import passwd # noqa diff --git a/server/jupyter_server/auth/__main__.py b/server/jupyter_server/auth/__main__.py deleted file mode 100644 index b34a318..0000000 --- a/server/jupyter_server/auth/__main__.py +++ /dev/null @@ -1,55 +0,0 @@ -import argparse -import sys -from getpass import getpass - -from jupyter_core.paths import jupyter_config_dir - -from jupyter_server.auth import passwd -from jupyter_server.config_manager import BaseJSONConfigManager - - -def set_password(args): - password = args.password - while not password: - password1 = getpass("" if args.quiet else "Provide password: ") - password_repeat = getpass("" if args.quiet else "Repeat password: ") - if password1 != password_repeat: - print("Passwords do not match, try again") - elif len(password1) < 4: - print("Please provide at least 4 characters") - else: - password = password1 - - password_hash = passwd(password) - cfg = BaseJSONConfigManager(config_dir=jupyter_config_dir()) - cfg.update( - "jupyter_server_config", - { - "ServerApp": { - "password": password_hash, - } - }, - ) - if not args.quiet: - print("password stored in config dir: %s" % jupyter_config_dir()) - - -def main(argv): - parser = argparse.ArgumentParser(argv[0]) - subparsers = parser.add_subparsers() - parser_password = subparsers.add_parser( - "password", help="sets a password for your jupyter server" - ) - parser_password.add_argument( - "password", - help="password to set, if not given, a password will be queried for (NOTE: this may not be safe)", - nargs="?", - ) - parser_password.add_argument("--quiet", help="suppress messages", action="https://github.com/store_true") - parser_password.set_defaults(function=set_password) - args = parser.parse_args(argv[1:]) - args.function(args) - - -if __name__ == "__main__": - main(sys.argv) diff --git a/server/jupyter_server/auth/authorizer.py b/server/jupyter_server/auth/authorizer.py deleted file mode 100644 index 952cb02..0000000 --- a/server/jupyter_server/auth/authorizer.py +++ /dev/null @@ -1,69 +0,0 @@ -"""An Authorizer for use in the Jupyter server. - -The default authorizer (AllowAllAuthorizer) -allows all authenticated requests - -.. versionadded:: 2.0 -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from traitlets.config import LoggingConfigurable - -from jupyter_server.base.handlers import JupyterHandler - - -class Authorizer(LoggingConfigurable): - """Base class for authorizing access to resources - in the Jupyter Server. - - All authorizers used in Jupyter Server - should inherit from this base class and, at the very minimum, - implement an `is_authorized` method with the - same signature as in this base class. - - The `is_authorized` method is called by the `@authorized` decorator - in JupyterHandler. If it returns True, the incoming request - to the server is accepted; if it returns False, the server - returns a 403 (Forbidden) error code. - - The authorization check will only be applied to requests - that have already been authenticated. - - .. versionadded:: 2.0 - """ - - def is_authorized(self, handler: JupyterHandler, user: str, action: str, resource: str) -> bool: - """A method to determine if `user` is authorized to perform `action` - (read, write, or execute) on the `resource` type. - - Parameters - ---------- - user : usually a dict or string - A truthy model representing the authenticated user. - A username string by default, - but usually a dict when integrating with an auth provider. - action : str - the category of action for the current request: read, write, or execute. - - resource : str - the type of resource (i.e. contents, kernels, files, etc.) the user is requesting. - - Returns True if user authorized to make request; otherwise, returns False. - """ - raise NotImplementedError() - - -class AllowAllAuthorizer(Authorizer): - """A no-op implementation of the Authorizer - - This authorizer allows all authenticated requests. - - .. versionadded:: 2.0 - """ - - def is_authorized(self, handler: JupyterHandler, user: str, action: str, resource: str) -> bool: - """This method always returns True. - - All authenticated users are allowed to do anything in the Jupyter Server. - """ - return True diff --git a/server/jupyter_server/auth/decorator.py b/server/jupyter_server/auth/decorator.py deleted file mode 100644 index 926808f..0000000 --- a/server/jupyter_server/auth/decorator.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Decorator for layering authorization into JupyterHandlers. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from functools import wraps -from typing import Callable -from typing import Optional -from typing import Union - -from tornado.log import app_log -from tornado.web import HTTPError - -from .utils import HTTP_METHOD_TO_AUTH_ACTION - - -def authorized( - action: Optional[Union[str, Callable]] = None, - resource: Optional[str] = None, - message: Optional[str] = None, -) -> Callable: - """A decorator for tornado.web.RequestHandler methods - that verifies whether the current user is authorized - to make the following request. - - Helpful for adding an 'authorization' layer to - a REST API. - - .. versionadded:: 2.0 - - Parameters - ---------- - action : str - the type of permission or action to check. - - resource: str or None - the name of the resource the action is being authorized - to access. - - message : str or none - a message for the unauthorized action. - """ - - def wrapper(method): - @wraps(method) - def inner(self, *args, **kwargs): - # default values for action, resource - nonlocal action - nonlocal resource - nonlocal message - if action is None: - http_method = self.request.method.upper() - action = HTTP_METHOD_TO_AUTH_ACTION[http_method] - if resource is None: - resource = self.auth_resource - if message is None: - message = f"User is not authorized to {action} on resource: {resource}." - - user = self.current_user - if not user: - app_log.warning("Attempting to authorize request without authentication!") - raise HTTPError(status_code=403, log_message=message) - # If the user is allowed to do this action, - # call the method. - if self.authorizer.is_authorized(self, user, action, resource): - return method(self, *args, **kwargs) - # else raise an exception. - else: - raise HTTPError(status_code=403, log_message=message) - - return inner - - if callable(action): - method = action - action = None - # no-arguments `@authorized` decorator called - return wrapper(method) - - return wrapper diff --git a/server/jupyter_server/auth/login.py b/server/jupyter_server/auth/login.py deleted file mode 100644 index fb245f7..0000000 --- a/server/jupyter_server/auth/login.py +++ /dev/null @@ -1,256 +0,0 @@ -"""Tornado handlers for logging into the Jupyter Server.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import re -import uuid -from urllib.parse import urlparse - -from tornado.escape import url_escape - -from ..base.handlers import JupyterHandler -from .security import passwd_check -from .security import set_password - - -class LoginHandler(JupyterHandler): - """The basic tornado login handler - - authenticates with a hashed password from the configuration. - """ - - def _render(self, message=None): - self.write( - self.render_template( - "login.html", - next=url_escape(self.get_argument("next", default=self.base_url)), - message=message, - ) - ) - - def _redirect_safe(self, url, default=None): - """Redirect if url is on our PATH - - Full-domain redirects are allowed if they pass our CORS origin checks. - - Otherwise use default (self.base_url if unspecified). - """ - if default is None: - default = self.base_url - # protect chrome users from mishandling unescaped backslashes. - # \ is not valid in urls, but some browsers treat it as / - # instead of %5C, causing `\\` to behave as `//` - url = url.replace("\\", "%5C") - parsed = urlparse(url) - if parsed.netloc or not (parsed.path + "/").startswith(self.base_url): - # require that next_url be absolute path within our path - allow = False - # OR pass our cross-origin check - if parsed.netloc: - # if full URL, run our cross-origin check: - origin = "%s://%s" % (parsed.scheme, parsed.netloc) - origin = origin.lower() - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(re.match(self.allow_origin_pat, origin)) - if not allow: - # not allowed, use default - self.log.warning("Not allowing login redirect to %r" % url) - url = default - self.redirect(url) - - def get(self): - if self.current_user: - next_url = self.get_argument("next", default=self.base_url) - self._redirect_safe(next_url) - else: - self._render() - - @property - def hashed_password(self): - return self.password_from_settings(self.settings) - - def passwd_check(self, a, b): - return passwd_check(a, b) - - def post(self): - typed_password = self.get_argument("password", default="") - new_password = self.get_argument("new_password", default="") - - if self.get_login_available(self.settings): - if self.passwd_check(self.hashed_password, typed_password) and not new_password: - self.set_login_cookie(self, uuid.uuid4().hex) - elif self.token and self.token == typed_password: - self.set_login_cookie(self, uuid.uuid4().hex) - if new_password and self.settings.get("allow_password_change"): - config_dir = self.settings.get("config_dir") - config_file = os.path.join(config_dir, "jupyter_server_config.json") - set_password(new_password, config_file=config_file) - self.log.info("Wrote hashed password to %s" % config_file) - else: - self.set_status(401) - self._render(message={"error": "Invalid credentials"}) - return - - next_url = self.get_argument("next", default=self.base_url) - self._redirect_safe(next_url) - - @classmethod - def set_login_cookie(cls, handler, user_id=None): - """Call this on handlers to set the login cookie for success""" - cookie_options = handler.settings.get("cookie_options", {}) - cookie_options.setdefault("httponly", True) - # tornado <4.2 has a bug that considers secure==True as soon as - # 'secure' kwarg is passed to set_secure_cookie - if handler.settings.get("secure_cookie", handler.request.protocol == "https"): - cookie_options.setdefault("secure", True) - cookie_options.setdefault("path", handler.base_url) - handler.set_secure_cookie(handler.cookie_name, user_id, **cookie_options) - return user_id - - auth_header_pat = re.compile(r"token\s+(.+)", re.IGNORECASE) - - @classmethod - def get_token(cls, handler): - """Get the user token from a request - - Default: - - - in URL parameters: ?token= - - in header: Authorization: token - """ - - user_token = handler.get_argument("token", "") - if not user_token: - # get it from Authorization header - m = cls.auth_header_pat.match(handler.request.headers.get("Authorization", "")) - if m: - user_token = m.group(1) - return user_token - - @classmethod - def should_check_origin(cls, handler): - """Should the Handler check for CORS origin validation? - - Origin check should be skipped for token-authenticated requests. - - Returns: - - True, if Handler must check for valid CORS origin. - - False, if Handler should skip origin check since requests are token-authenticated. - """ - return not cls.is_token_authenticated(handler) - - @classmethod - def is_token_authenticated(cls, handler): - """Returns True if handler has been token authenticated. Otherwise, False. - - Login with a token is used to signal certain things, such as: - - - permit access to REST API - - xsrf protection - - skip origin-checks for scripts - """ - if getattr(handler, "_user_id", None) is None: - # ensure get_user has been called, so we know if we're token-authenticated - handler.get_current_user() - return getattr(handler, "_token_authenticated", False) - - @classmethod - def get_user(cls, handler): - """Called by handlers.get_current_user for identifying the current user. - - See tornado.web.RequestHandler.get_current_user for details. - """ - # Can't call this get_current_user because it will collide when - # called on LoginHandler itself. - if getattr(handler, "_user_id", None): - return handler._user_id - user_id = cls.get_user_token(handler) - if user_id is None: - get_secure_cookie_kwargs = handler.settings.get("get_secure_cookie_kwargs", {}) - user_id = handler.get_secure_cookie(handler.cookie_name, **get_secure_cookie_kwargs) - if user_id: - user_id = user_id.decode() - else: - cls.set_login_cookie(handler, user_id) - # Record that the current request has been authenticated with a token. - # Used in is_token_authenticated above. - handler._token_authenticated = True - if user_id is None: - # If an invalid cookie was sent, clear it to prevent unnecessary - # extra warnings. But don't do this on a request with *no* cookie, - # because that can erroneously log you out (see gh-3365) - if handler.get_cookie(handler.cookie_name) is not None: - handler.log.warning("Clearing invalid/expired login cookie %s", handler.cookie_name) - handler.clear_login_cookie() - if not handler.login_available: - # Completely insecure! No authentication at all. - # No need to warn here, though; validate_security will have already done that. - user_id = "anonymous" - - # cache value for future retrievals on the same request - handler._user_id = user_id - return user_id - - @classmethod - def get_user_token(cls, handler): - """Identify the user based on a token in the URL or Authorization header - - Returns: - - uuid if authenticated - - None if not - """ - token = handler.token - if not token: - return - # check login token from URL argument or Authorization header - user_token = cls.get_token(handler) - authenticated = False - if user_token == token: - # token-authenticated, set the login cookie - handler.log.debug( - "Accepting token-authenticated connection from %s", - handler.request.remote_ip, - ) - authenticated = True - - if authenticated: - return uuid.uuid4().hex - else: - return None - - @classmethod - def validate_security(cls, app, ssl_options=None): - """Check the application's security. - - Show messages, or abort if necessary, based on the security configuration. - """ - if not app.ip: - warning = "WARNING: The Jupyter server is listening on all IP addresses" - if ssl_options is None: - app.log.warning(warning + " and not using encryption. This " "is not recommended.") - if not app.password and not app.token: - app.log.warning( - warning + " and not using authentication. " - "This is highly insecure and not recommended." - ) - else: - if not app.password and not app.token: - app.log.warning( - "All authentication is disabled." - " Anyone who can connect to this server will be able to run code." - ) - - @classmethod - def password_from_settings(cls, settings): - """Return the hashed password from the tornado settings. - - If there is no configured password, an empty string will be returned. - """ - return settings.get("password", "") - - @classmethod - def get_login_available(cls, settings): - """Whether this LoginHandler is needed - and therefore whether the login page should be displayed.""" - return bool(cls.password_from_settings(settings) or settings.get("token")) diff --git a/server/jupyter_server/auth/logout.py b/server/jupyter_server/auth/logout.py deleted file mode 100644 index 49b98bd..0000000 --- a/server/jupyter_server/auth/logout.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Tornado handlers for logging out of the Jupyter Server. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from ..base.handlers import JupyterHandler - - -class LogoutHandler(JupyterHandler): - def get(self): - self.clear_login_cookie() - if self.login_available: - message = {"info": "Successfully logged out."} - else: - message = {"warning": "Cannot log out. Kennen Server authentication " "is disabled."} - self.write(self.render_template("logout.html", message=message)) - - -default_handlers = [(r"/logout", LogoutHandler)] diff --git a/server/jupyter_server/auth/security.py b/server/jupyter_server/auth/security.py deleted file mode 100644 index 3c6bbad..0000000 --- a/server/jupyter_server/auth/security.py +++ /dev/null @@ -1,178 +0,0 @@ -""" -Password generation for the Jupyter Server. -""" -import getpass -import hashlib -import io -import json -import os -import random -import traceback -import warnings -from contextlib import contextmanager - -from ipython_genutils.py3compat import cast_bytes -from ipython_genutils.py3compat import cast_unicode -from ipython_genutils.py3compat import str_to_bytes -from jupyter_core.paths import jupyter_config_dir -from traitlets.config import Config -from traitlets.config import ConfigFileNotFound -from traitlets.config import JSONFileConfigLoader - -# Length of the salt in nr of hex chars, which implies salt_len * 4 -# bits of randomness. -salt_len = 12 - - -def passwd(passphrase=None, algorithm="argon2"): - """Generate hashed password and salt for use in server configuration. - - In the server configuration, set `c.ServerApp.password` to - the generated string. - - Parameters - ---------- - passphrase : str - Password to hash. If unspecified, the user is asked to input - and verify a password. - algorithm : str - Hashing algorithm to use (e.g, 'sha1' or any argument supported - by :func:`hashlib.new`, or 'argon2'). - - Returns - ------- - hashed_passphrase : str - Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'. - - Examples - -------- - >>> passwd('mypassword') # doctest: +ELLIPSIS - 'argon2:...' - - """ - if passphrase is None: - for i in range(3): - p0 = getpass.getpass("Enter password: ") - p1 = getpass.getpass("Verify password: ") - if p0 == p1: - passphrase = p0 - break - else: - print("Passwords do not match.") - else: - raise ValueError("No matching passwords found. Giving up.") - - if algorithm == "argon2": - import argon2 - - ph = argon2.PasswordHasher( - memory_cost=10240, - time_cost=10, - parallelism=8, - ) - h = ph.hash(passphrase) - - return ":".join((algorithm, cast_unicode(h, "ascii"))) - - h = hashlib.new(algorithm) - salt = ("%0" + str(salt_len) + "x") % random.getrandbits(4 * salt_len) - h.update(cast_bytes(passphrase, "utf-8") + str_to_bytes(salt, "ascii")) - - return ":".join((algorithm, salt, h.hexdigest())) - - -def passwd_check(hashed_passphrase, passphrase): - """Verify that a given passphrase matches its hashed version. - - Parameters - ---------- - hashed_passphrase : str - Hashed password, in the format returned by `passwd`. - passphrase : str - Passphrase to validate. - - Returns - ------- - valid : bool - True if the passphrase matches the hash. - - Examples - -------- - >>> myhash = passwd('mypassword') - >>> passwd_check(myhash, 'mypassword') - True - - >>> passwd_check(myhash, 'otherpassword') - False - - >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a', - ... 'mypassword') - True - """ - if hashed_passphrase.startswith("argon2:"): - import argon2 - import argon2.exceptions - - ph = argon2.PasswordHasher() - - try: - return ph.verify(hashed_passphrase[7:], passphrase) - except argon2.exceptions.VerificationError: - return False - - try: - algorithm, salt, pw_digest = hashed_passphrase.split(":", 2) - except (ValueError, TypeError): - return False - - try: - h = hashlib.new(algorithm) - except ValueError: - return False - - if len(pw_digest) == 0: - return False - - h.update(cast_bytes(passphrase, "utf-8") + cast_bytes(salt, "ascii")) - - return h.hexdigest() == pw_digest - - -@contextmanager -def persist_config(config_file=None, mode=0o600): - """Context manager that can be used to modify a config object - - On exit of the context manager, the config will be written back to disk, - by default with user-only (600) permissions. - """ - - if config_file is None: - config_file = os.path.join(jupyter_config_dir(), "jupyter_server_config.json") - - os.makedirs(os.path.dirname(config_file), exist_ok=True) - - loader = JSONFileConfigLoader(os.path.basename(config_file), os.path.dirname(config_file)) - try: - config = loader.load_config() - except ConfigFileNotFound: - config = Config() - - yield config - - with io.open(config_file, "w", encoding="utf8") as f: - f.write(cast_unicode(json.dumps(config, indent=2))) - - try: - os.chmod(config_file, mode) - except Exception as e: - tb = traceback.format_exc() - warnings.warn("Failed to set permissions on %s:\n%s" % (config_file, tb), RuntimeWarning) - - -def set_password(password=None, config_file=None): - """Ask user for password, store it in JSON configuration file""" - - hashed_password = passwd(password) - - with persist_config(config_file) as config: - config.ServerApp.password = hashed_password diff --git a/server/jupyter_server/auth/utils.py b/server/jupyter_server/auth/utils.py deleted file mode 100644 index 5336235..0000000 --- a/server/jupyter_server/auth/utils.py +++ /dev/null @@ -1,66 +0,0 @@ -"""A module with various utility methods for authorization in Jupyter Server. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import importlib -import re - - -HTTP_METHOD_TO_AUTH_ACTION = { - "GET": "read", - "HEAD": "read", - "OPTIONS": "read", - "POST": "write", - "PUT": "write", - "PATCH": "write", - "DELETE": "write", - "WEBSOCKET": "execute", -} - - -def get_regex_to_resource_map(): - """Returns a dictionary with all of Jupyter Server's - request handler URL regex patterns mapped to - their resource name. - - e.g. - { "/api/contents/": "contents", ...} - """ - from jupyter_server.serverapp import JUPYTER_SERVICE_HANDLERS - - modules = [] - for mod in JUPYTER_SERVICE_HANDLERS.values(): - if mod: - modules.extend(mod) - resource_map = {} - for handler_module in modules: - mod = importlib.import_module(handler_module) - name = mod.AUTH_RESOURCE - for handler in mod.default_handlers: - url_regex = handler[0] - resource_map[url_regex] = name - # terminal plugin doesn't have importable url patterns - # get these from terminal/__init__.py - for url_regex in [ - r"/terminals/websocket/(\w+)", - "/api/terminals", - r"/api/terminals/(\w+)", - ]: - resource_map[url_regex] = "terminals" - return resource_map - - -def match_url_to_resource(url, regex_mapping=None): - """Finds the JupyterHandler regex pattern that would - match the given URL and returns the resource name (str) - of that handler. - - e.g. - /api/contents/... returns "contents" - """ - if not regex_mapping: - regex_mapping = get_regex_to_resource_map() - for regex, auth_resource in regex_mapping.items(): - pattern = re.compile(regex) - if pattern.fullmatch(url): - return auth_resource diff --git a/server/jupyter_server/base/__init__.py b/server/jupyter_server/base/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/base/handlers.py b/server/jupyter_server/base/handlers.py deleted file mode 100644 index 0361b12..0000000 --- a/server/jupyter_server/base/handlers.py +++ /dev/null @@ -1,987 +0,0 @@ -"""Base Tornado handlers for the Jupyter server.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import datetime -import functools -import ipaddress -import json -import mimetypes -import os -import re -import traceback -import types -import warnings -from http.client import responses -from http.cookies import Morsel -from urllib.parse import urlparse - -import prometheus_client -from ipython_genutils.path import filefind -from jinja2 import TemplateNotFound -from jupyter_core.paths import is_hidden -from tornado import escape -from tornado import httputil -from tornado import web -from tornado.log import app_log -from traitlets.config import Application - -import jupyter_server -from jupyter_server._sysinfo import get_sys_info -from jupyter_server._tz import utcnow -from jupyter_server.i18n import combine_translations -from jupyter_server.services.security import csp_report_uri -from jupyter_server.utils import ensure_async -from jupyter_server.utils import url_escape -from jupyter_server.utils import url_is_absolute -from jupyter_server.utils import url_path_join -from jupyter_server.utils import urldecode_unix_socket_path - -# ----------------------------------------------------------------------------- -# Top-level handlers -# ----------------------------------------------------------------------------- -non_alphanum = re.compile(r"[^A-Za-z0-9]") - -_sys_info_cache = None - - -def json_sys_info(): - global _sys_info_cache - if _sys_info_cache is None: - _sys_info_cache = json.dumps(get_sys_info()) - return _sys_info_cache - - -def log(): - if Application.initialized(): - return Application.instance().log - else: - return app_log - - -class AuthenticatedHandler(web.RequestHandler): - """A RequestHandler with an authenticated user.""" - - @property - def content_security_policy(self): - """The default Content-Security-Policy header - - Can be overridden by defining Content-Security-Policy in settings['headers'] - """ - if "Content-Security-Policy" in self.settings.get("headers", {}): - # user-specified, don't override - return self.settings["headers"]["Content-Security-Policy"] - - return "; ".join( - [ - "frame-ancestors 'self'", - # Make sure the report-uri is relative to the base_url - "report-uri " - + self.settings.get("csp_report_uri", url_path_join(self.base_url, csp_report_uri)), - ] - ) - - def set_default_headers(self): - headers = {} - headers["X-Content-Type-Options"] = "nosniff" - headers.update(self.settings.get("headers", {})) - - headers["Content-Security-Policy"] = self.content_security_policy - - # Allow for overriding headers - for header_name, value in headers.items(): - try: - self.set_header(header_name, value) - except Exception as e: - # tornado raise Exception (not a subclass) - # if method is unsupported (websocket and Access-Control-Allow-Origin - # for example, so just ignore) - self.log.debug(e) - - def force_clear_cookie(self, name, path="/", domain=None): - """Deletes the cookie with the given name. - - Tornado's cookie handling currently (Jan 2018) stores cookies in a dict - keyed by name, so it can only modify one cookie with a given name per - response. The browser can store multiple cookies with the same name - but different domains and/or paths. This method lets us clear multiple - cookies with the same name. - - Due to limitations of the cookie protocol, you must pass the same - path and domain to clear a cookie as were used when that cookie - was set (but there is no way to find out on the server side - which values were used for a given cookie). - """ - name = escape.native_str(name) - expires = datetime.datetime.utcnow() - datetime.timedelta(days=365) - - morsel = Morsel() - morsel.set(name, "", '""') - morsel["expires"] = httputil.format_timestamp(expires) - morsel["path"] = path - if domain: - morsel["domain"] = domain - self.add_header("Set-Cookie", morsel.OutputString()) - - def clear_login_cookie(self): - cookie_options = self.settings.get("cookie_options", {}) - path = cookie_options.setdefault("path", self.base_url) - self.clear_cookie(self.cookie_name, path=path) - if path and path != "/": - # also clear cookie on / to ensure old cookies are cleared - # after the change in path behavior. - # N.B. This bypasses the normal cookie handling, which can't update - # two cookies with the same name. See the method above. - self.force_clear_cookie(self.cookie_name) - - def get_current_user(self): - if self.login_handler is None: - return "anonymous" - return self.login_handler.get_user(self) - - def skip_check_origin(self): - """Ask my login_handler if I should skip the origin_check - - For example: in the default LoginHandler, if a request is token-authenticated, - origin checking should be skipped. - """ - if self.request.method == "OPTIONS": - # no origin-check on options requests, which are used to check origins! - return True - if self.login_handler is None or not hasattr(self.login_handler, "should_check_origin"): - return False - return not self.login_handler.should_check_origin(self) - - @property - def token_authenticated(self): - """Have I been authenticated with a token?""" - if self.login_handler is None or not hasattr(self.login_handler, "is_token_authenticated"): - return False - return self.login_handler.is_token_authenticated(self) - - @property - def cookie_name(self): - default_cookie_name = non_alphanum.sub("-", "username-{}".format(self.request.host)) - return self.settings.get("cookie_name", default_cookie_name) - - @property - def logged_in(self): - """Is a user currently logged in?""" - user = self.get_current_user() - return user and not user == "anonymous" - - @property - def login_handler(self): - """Return the login handler for this application, if any.""" - return self.settings.get("login_handler_class", None) - - @property - def token(self): - """Return the login token for this application, if any.""" - return self.settings.get("token", None) - - @property - def login_available(self): - """May a user proceed to log in? - - This returns True if login capability is available, irrespective of - whether the user is already logged in or not. - - """ - if self.login_handler is None: - return False - return bool(self.login_handler.get_login_available(self.settings)) - - @property - def authorizer(self): - return self.settings["authorizer"] - - -class JupyterHandler(AuthenticatedHandler): - """Jupyter-specific extensions to authenticated handling - - Mostly property shortcuts to Jupyter-specific settings. - """ - - @property - def config(self): - return self.settings.get("config", None) - - @property - def log(self): - """use the Jupyter log by default, falling back on tornado's logger""" - return log() - - @property - def jinja_template_vars(self): - """User-supplied values to supply to jinja templates.""" - return self.settings.get("jinja_template_vars", {}) - - @property - def serverapp(self): - return self.settings["serverapp"] - - # --------------------------------------------------------------- - # URLs - # --------------------------------------------------------------- - - @property - def version_hash(self): - """The version hash to use for cache hints for static files""" - return self.settings.get("version_hash", "") - - @property - def mathjax_url(https://github.com/self): - url = self.settings.get("mathjax_url", "") - if not url or url_is_absolute(url): - return url - return url_path_join(self.base_url, url) - - @property - def mathjax_config(self): - return self.settings.get("mathjax_config", "TeX-AMS-MML_HTMLorMML-full,Safe") - - @property - def base_url(https://github.com/self): - return self.settings.get("base_url", "/") - - @property - def default_url(https://github.com/self): - return self.settings.get("default_url", "") - - @property - def ws_url(https://github.com/self): - return self.settings.get("websocket_url", "") - - @property - def contents_js_source(self): - self.log.debug( - "Using contents: %s", - self.settings.get("contents_js_source", "services/contents"), - ) - return self.settings.get("contents_js_source", "services/contents") - - # --------------------------------------------------------------- - # Manager objects - # --------------------------------------------------------------- - - @property - def kernel_manager(self): - return self.settings["kernel_manager"] - - @property - def contents_manager(self): - return self.settings["contents_manager"] - - @property - def session_manager(self): - return self.settings["session_manager"] - - @property - def terminal_manager(self): - return self.settings["terminal_manager"] - - @property - def kernel_spec_manager(self): - return self.settings["kernel_spec_manager"] - - @property - def config_manager(self): - return self.settings["config_manager"] - - # --------------------------------------------------------------- - # CORS - # --------------------------------------------------------------- - - @property - def allow_origin(self): - """Normal Access-Control-Allow-Origin""" - return self.settings.get("allow_origin", "") - - @property - def allow_origin_pat(self): - """Regular expression version of allow_origin""" - return self.settings.get("allow_origin_pat", None) - - @property - def allow_credentials(self): - """Whether to set Access-Control-Allow-Credentials""" - return self.settings.get("allow_credentials", False) - - def set_default_headers(self): - """Add CORS headers, if defined""" - super(JupyterHandler, self).set_default_headers() - if self.allow_origin: - self.set_header("Access-Control-Allow-Origin", self.allow_origin) - elif self.allow_origin_pat: - origin = self.get_origin() - if origin and re.match(self.allow_origin_pat, origin): - self.set_header("Access-Control-Allow-Origin", origin) - elif self.token_authenticated and "Access-Control-Allow-Origin" not in self.settings.get( - "headers", {} - ): - # allow token-authenticated requests cross-origin by default. - # only apply this exception if allow-origin has not been specified. - self.set_header("Access-Control-Allow-Origin", self.request.headers.get("Origin", "")) - - if self.allow_credentials: - self.set_header("Access-Control-Allow-Credentials", "true") - - def set_attachment_header(self, filename): - """Set Content-Disposition: attachment header - - As a method to ensure handling of filename encoding - """ - escaped_filename = url_escape(filename) - self.set_header( - "Content-Disposition", - "attachment;" - " filename*=utf-8''{utf8}".format( - utf8=escaped_filename, - ), - ) - - def get_origin(self): - # Handle WebSocket Origin naming convention differences - # The difference between version 8 and 13 is that in 8 the - # client sends a "Sec-Websocket-Origin" header and in 13 it's - # simply "Origin". - if "Origin" in self.request.headers: - origin = self.request.headers.get("Origin") - else: - origin = self.request.headers.get("Sec-Websocket-Origin", None) - return origin - - # origin_to_satisfy_tornado is present because tornado requires - # check_origin to take an origin argument, but we don't use it - def check_origin(self, origin_to_satisfy_tornado=""): - """Check Origin for cross-site API requests, including websockets - - Copied from WebSocket with changes: - - - allow unspecified host/origin (e.g. scripts) - - allow token-authenticated requests - """ - if self.allow_origin == "*" or self.skip_check_origin(): - return True - - host = self.request.headers.get("Host") - origin = self.request.headers.get("Origin") - - # If no header is provided, let the request through. - # Origin can be None for: - # - same-origin (IE, Firefox) - # - Cross-site POST form (IE, Firefox) - # - Scripts - # The cross-site POST (XSRF) case is handled by tornado's xsrf_token - if origin is None or host is None: - return True - - origin = origin.lower() - origin_host = urlparse(origin).netloc - - # OK if origin matches host - if origin_host == host: - return True - - # Check CORS headers - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(re.match(self.allow_origin_pat, origin)) - else: - # No CORS headers deny the request - allow = False - if not allow: - self.log.warning( - "Blocking Cross Origin API request for %s. Origin: %s, Host: %s", - self.request.path, - origin, - host, - ) - return allow - - def check_referer(self): - """Check Referer for cross-site requests. - Disables requests to certain endpoints with - external or missing Referer. - If set, allow_origin settings are applied to the Referer - to whitelist specific cross-origin sites. - Used on GET for api endpoints and /files/ - to block cross-site inclusion (XSSI). - """ - if self.allow_origin == "*" or self.skip_check_origin(): - return True - - host = self.request.headers.get("Host") - referer = self.request.headers.get("Referer") - - if not host: - self.log.warning("Blocking request with no host") - return False - if not referer: - self.log.warning("Blocking request with no referer") - return False - - referer_url = urlparse(referer) - referer_host = referer_url.netloc - if referer_host == host: - return True - - # apply cross-origin checks to Referer: - origin = "{}://{}".format(referer_url.scheme, referer_url.netloc) - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(re.match(self.allow_origin_pat, origin)) - else: - # No CORS settings, deny the request - allow = False - - if not allow: - self.log.warning( - "Blocking Cross Origin request for %s. Referer: %s, Host: %s", - self.request.path, - origin, - host, - ) - return allow - - def check_xsrf_cookie(self): - """Bypass xsrf cookie checks when token-authenticated""" - if self.token_authenticated or self.settings.get("disable_check_xsrf", False): - # Token-authenticated requests do not need additional XSRF-check - # Servers without authentication are vulnerable to XSRF - return - try: - return super(JupyterHandler, self).check_xsrf_cookie() - except web.HTTPError as e: - if self.request.method in {"GET", "HEAD"}: - # Consider Referer a sufficient cross-origin check for GET requests - if not self.check_referer(): - referer = self.request.headers.get("Referer") - if referer: - msg = "Blocking Cross Origin request from {}.".format(referer) - else: - msg = "Blocking request from unknown origin" - raise web.HTTPError(403, msg) - else: - raise - - def check_host(self): - """Check the host header if remote access disallowed. - - Returns True if the request should continue, False otherwise. - """ - if self.settings.get("allow_remote_access", False): - return True - - # Remove port (e.g. ':8888') from host - host = re.match(r"^(.*?)(:\d+)?$", self.request.host).group(1) - - # Browsers format IPv6 addresses like [::1]; we need to remove the [] - if host.startswith("[") and host.endswith("]"): - host = host[1:-1] - - # UNIX socket handling - check_host = urldecode_unix_socket_path(host) - if check_host.startswith("/") and os.path.exists(check_host): - allow = True - else: - try: - addr = ipaddress.ip_address(host) - except ValueError: - # Not an IP address: check against hostnames - allow = host in self.settings.get("local_hostnames", ["localhost"]) - else: - allow = addr.is_loopback - - if not allow: - self.log.warning( - ( - "Blocking request with non-local 'Host' %s (%s). " - "If the server should be accessible at that name, " - "set ServerApp.allow_remote_access to disable the check." - ), - host, - self.request.host, - ) - return allow - - def prepare(self): - if not self.check_host(): - raise web.HTTPError(403) - return super(JupyterHandler, self).prepare() - - # --------------------------------------------------------------- - # template rendering - # --------------------------------------------------------------- - - def get_template(self, name): - """Return the jinja template object for a given name""" - return self.settings["jinja2_env"].get_template(name) - - def render_template(self, name, **ns): - ns.update(self.template_namespace) - template = self.get_template(name) - return template.render(**ns) - - @property - def template_namespace(self): - return dict( - base_url=self.base_url, - default_url=self.default_url, - ws_url=self.ws_url, - logged_in=self.logged_in, - allow_password_change=self.settings.get("allow_password_change"), - login_available=self.login_available, - token_available=bool(self.token), - static_url=self.static_url, - sys_info=json_sys_info(), - contents_js_source=self.contents_js_source, - version_hash=self.version_hash, - xsrf_form_html=self.xsrf_form_html, - token=self.token, - xsrf_token=self.xsrf_token.decode("utf8"), - nbjs_translations=json.dumps( - combine_translations(self.request.headers.get("Accept-Language", "")) - ), - **self.jinja_template_vars - ) - - def get_json_body(self): - """Return the body of the request as JSON data.""" - if not self.request.body: - return None - # Do we need to call body.decode('utf-8') here? - body = self.request.body.strip().decode("utf-8") - try: - model = json.loads(body) - except Exception as e: - self.log.debug("Bad JSON: %r", body) - self.log.error("Couldn't parse JSON", exc_info=True) - raise web.HTTPError(400, "Invalid JSON in body of request") from e - return model - - def write_error(self, status_code, **kwargs): - """render custom error pages""" - exc_info = kwargs.get("exc_info") - message = "" - status_message = responses.get(status_code, "Unknown HTTP Error") - exception = "(unknown)" - if exc_info: - exception = exc_info[1] - # get the custom message, if defined - try: - message = exception.log_message % exception.args - except Exception: - pass - - # construct the custom reason, if defined - reason = getattr(exception, "reason", "") - if reason: - status_message = reason - - # build template namespace - ns = dict( - status_code=status_code, - status_message=status_message, - message=message, - exception=exception, - ) - - self.set_header("Content-Type", "text/html") - # render the template - try: - html = self.render_template("%s.html" % status_code, **ns) - except TemplateNotFound: - html = self.render_template("error.html", **ns) - - self.write(html) - - -class APIHandler(JupyterHandler): - """Base class for API handlers""" - - def prepare(self): - if not self.check_origin(): - raise web.HTTPError(404) - return super(APIHandler, self).prepare() - - def write_error(self, status_code, **kwargs): - """APIHandler errors are JSON, not human pages""" - self.set_header("Content-Type", "application/json") - message = responses.get(status_code, "Unknown HTTP Error") - reply = { - "message": message, - } - exc_info = kwargs.get("exc_info") - if exc_info: - e = exc_info[1] - if isinstance(e, HTTPError): - reply["message"] = e.log_message or message - reply["reason"] = e.reason - else: - reply["message"] = "Unhandled error" - reply["reason"] = None - reply["traceback"] = "".join(traceback.format_exception(*exc_info)) - self.log.warning(reply["message"]) - self.finish(json.dumps(reply)) - - def get_current_user(self): - """Raise 403 on API handlers instead of redirecting to human login page""" - # preserve _user_cache so we don't raise more than once - if hasattr(self, "_user_cache"): - return self._user_cache - self._user_cache = user = super(APIHandler, self).get_current_user() - return user - - def get_login_url(https://github.com/self): - # if get_login_url is invoked in an API handler, - # that means @web.authenticated is trying to trigger a redirect. - # instead of redirecting, raise 403 instead. - if not self.current_user: - raise web.HTTPError(403) - return super(APIHandler, self).get_login_url() - - @property - def content_security_policy(self): - csp = "; ".join( - [ - super(APIHandler, self).content_security_policy, - "default-src 'none'", - ] - ) - return csp - - # set _track_activity = False on API handlers that shouldn't track activity - _track_activity = True - - def update_api_activity(self): - """Update last_activity of API requests""" - # record activity of authenticated requests - if ( - self._track_activity - and getattr(self, "_user_cache", None) - and self.get_argument("no_track_activity", None) is None - ): - self.settings["api_last_activity"] = utcnow() - - def finish(self, *args, **kwargs): - self.update_api_activity() - self.set_header("Content-Type", "application/json") - return super(APIHandler, self).finish(*args, **kwargs) - - def options(self, *args, **kwargs): - if "Access-Control-Allow-Headers" in self.settings.get("headers", {}): - self.set_header( - "Access-Control-Allow-Headers", - self.settings["headers"]["Access-Control-Allow-Headers"], - ) - else: - self.set_header( - "Access-Control-Allow-Headers", - "accept, content-type, authorization, x-xsrftoken", - ) - self.set_header("Access-Control-Allow-Methods", "GET, PUT, POST, PATCH, DELETE, OPTIONS") - - # if authorization header is requested, - # that means the request is token-authenticated. - # avoid browser-side rejection of the preflight request. - # only allow this exception if allow_origin has not been specified - # and Jupyter server authentication is enabled. - # If the token is not valid, the 'real' request will still be rejected. - requested_headers = self.request.headers.get("Access-Control-Request-Headers", "").split( - "," - ) - if ( - requested_headers - and any(h.strip().lower() == "authorization" for h in requested_headers) - and ( - # FIXME: it would be even better to check specifically for token-auth, - # but there is currently no API for this. - self.login_available - ) - and ( - self.allow_origin - or self.allow_origin_pat - or "Access-Control-Allow-Origin" in self.settings.get("headers", {}) - ) - ): - self.set_header("Access-Control-Allow-Origin", self.request.headers.get("Origin", "")) - - -class Template404(JupyterHandler): - """Render our 404 template""" - - def prepare(self): - raise web.HTTPError(404) - - -class AuthenticatedFileHandler(JupyterHandler, web.StaticFileHandler): - """static files should only be accessible when logged in""" - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the Jupyter server. - return ( - super(AuthenticatedFileHandler, self).content_security_policy - + "; sandbox allow-scripts" - ) - - @web.authenticated - def head(self, path): - self.check_xsrf_cookie() - return super(AuthenticatedFileHandler, self).head(path) - - @web.authenticated - def get(self, path): - if os.path.splitext(path)[1] == ".ipynb" or self.get_argument("download", False): - name = path.rsplit("/", 1)[-1] - self.set_attachment_header(name) - - return web.StaticFileHandler.get(self, path) - - def get_content_type(self): - path = self.absolute_path.strip("/") - if "/" in path: - _, name = path.rsplit("/", 1) - else: - name = path - if name.endswith(".ipynb"): - return "application/x-ipynb+json" - else: - cur_mime = mimetypes.guess_type(name)[0] - if cur_mime == "text/plain": - return "text/plain; charset=UTF-8" - else: - return super(AuthenticatedFileHandler, self).get_content_type() - - def set_headers(self): - super(AuthenticatedFileHandler, self).set_headers() - # disable browser caching, rely on 304 replies for savings - if "v" not in self.request.arguments: - self.add_header("Cache-Control", "no-cache") - - def compute_etag(self): - return None - - def validate_absolute_path(self, root, absolute_path): - """Validate and return the absolute path. - - Requires tornado 3.1 - - Adding to tornado's own handling, forbids the serving of hidden files. - """ - abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path) - abs_root = os.path.abspath(root) - if is_hidden(abs_path, abs_root) and not self.contents_manager.allow_hidden: - self.log.info( - "Refusing to serve hidden file, via 404 Error, use flag 'ContentsManager.allow_hidden' to enable" - ) - raise web.HTTPError(404) - return abs_path - - -def json_errors(method): - """Decorate methods with this to return GitHub style JSON errors. - - This should be used on any JSON API on any handler method that can raise HTTPErrors. - - This will grab the latest HTTPError exception using sys.exc_info - and then: - - 1. Set the HTTP status code based on the HTTPError - 2. Create and return a JSON body with a message field describing - the error in a human readable form. - """ - warnings.warn( - "@json_errors is deprecated in notebook 5.2.0. Subclass APIHandler instead.", - DeprecationWarning, - stacklevel=2, - ) - - @functools.wraps(method) - def wrapper(self, *args, **kwargs): - self.write_error = types.MethodType(APIHandler.write_error, self) - return method(self, *args, **kwargs) - - return wrapper - - -# ----------------------------------------------------------------------------- -# File handler -# ----------------------------------------------------------------------------- - -# to minimize subclass changes: -HTTPError = web.HTTPError - - -class FileFindHandler(JupyterHandler, web.StaticFileHandler): - """subclass of StaticFileHandler for serving files from a search path""" - - # cache search results, don't search for files more than once - _static_paths = {} - - def set_headers(self): - super(FileFindHandler, self).set_headers() - # disable browser caching, rely on 304 replies for savings - if "v" not in self.request.arguments or any( - self.request.path.startswith(path) for path in self.no_cache_paths - ): - self.set_header("Cache-Control", "no-cache") - - def initialize(self, path, default_filename=None, no_cache_paths=None): - self.no_cache_paths = no_cache_paths or [] - - if isinstance(path, str): - path = [path] - - self.root = tuple(os.path.abspath(os.path.expanduser(p)) + os.sep for p in path) - self.default_filename = default_filename - - def compute_etag(self): - return None - - @classmethod - def get_absolute_path(cls, roots, path): - """locate a file to serve on our static file search path""" - with cls._lock: - if path in cls._static_paths: - return cls._static_paths[path] - try: - abspath = os.path.abspath(filefind(path, roots)) - except IOError: - # IOError means not found - return "" - - cls._static_paths[path] = abspath - - log().debug("Path %s served from %s" % (path, abspath)) - return abspath - - def validate_absolute_path(self, root, absolute_path): - """check if the file should be served (raises 404, 403, etc.)""" - if absolute_path == "": - raise web.HTTPError(404) - - for root in self.root: - if (absolute_path + os.sep).startswith(root): - break - - return super(FileFindHandler, self).validate_absolute_path(root, absolute_path) - - -class APIVersionHandler(APIHandler): - def get(self): - # not authenticated, so give as few info as possible - self.finish(json.dumps({"version": jupyter_server.__version__})) - - -class TrailingSlashHandler(web.RequestHandler): - """Simple redirect handler that strips trailing slashes - - This should be the first, highest priority handler. - """ - - def get(self): - path, *rest = self.request.uri.partition("?") - # trim trailing *and* leading / - # to avoid misinterpreting repeated '//' - path = "/" + path.strip("/") - new_uri = "".join([path, *rest]) - self.redirect(new_uri) - - post = put = get - - -class MainHandler(JupyterHandler): - """Simple handler for base_url.""" - - def get(self): - html = self.render_template("main.html") - self.write(html) - - post = put = get - - -class FilesRedirectHandler(JupyterHandler): - """Handler for redirecting relative URLs to the /files/ handler""" - - @staticmethod - async def redirect_to_files(self, path): - """make redirect logic a reusable static method - - so it can be called from other handlers. - """ - cm = self.contents_manager - if await ensure_async(cm.dir_exists(path)): - # it's a *directory*, redirect to /tree - url = url_path_join(self.base_url, "tree", url_escape(path)) - else: - orig_path = path - # otherwise, redirect to /files - parts = path.split("/") - - if not await ensure_async(cm.file_exists(path=path)) and "files" in parts: - # redirect without files/ iff it would 404 - # this preserves pre-2.0-style 'files/' links - self.log.warning("Deprecated files/ URL: %s", orig_path) - parts.remove("files") - path = "/".join(parts) - - if not await ensure_async(cm.file_exists(path=path)): - raise web.HTTPError(404) - - url = url_path_join(self.base_url, "files", url_escape(path)) - self.log.debug("Redirecting %s to %s", self.request.path, url) - self.redirect(url) - - def get(self, path=""): - return self.redirect_to_files(self, path) - - -class RedirectWithParams(web.RequestHandler): - """Sam as web.RedirectHandler, but preserves URL parameters""" - - def initialize(self, url, permanent=True): - self._url = url - self._permanent = permanent - - def get(self): - sep = "&" if "?" in self._url else "?" - url = sep.join([self._url, self.request.query]) - self.redirect(url, permanent=self._permanent) - - -class PrometheusMetricsHandler(JupyterHandler): - """ - Return prometheus metrics for this notebook server - """ - - def get(self): - if self.settings["authenticate_prometheus"] and not self.logged_in: - raise web.HTTPError(403) - - self.set_header("Content-Type", prometheus_client.CONTENT_TYPE_LATEST) - self.write(prometheus_client.generate_latest(prometheus_client.REGISTRY)) - - -# ----------------------------------------------------------------------------- -# URL pattern fragments for re-use -# ----------------------------------------------------------------------------- - -# path matches any number of `/foo[/bar...]` or just `/` or '' -path_regex = r"(?P(?:(?:/[^/]+)+|/?))" - -# ----------------------------------------------------------------------------- -# URL to handler mappings -# ----------------------------------------------------------------------------- - - -default_handlers = [ - (r".*/", TrailingSlashHandler), - (r"api", APIVersionHandler), - (r"/(robots\.txt|favicon\.ico)", web.StaticFileHandler), - (r"/metrics", PrometheusMetricsHandler), -] diff --git a/server/jupyter_server/base/zmqhandlers.py b/server/jupyter_server/base/zmqhandlers.py deleted file mode 100644 index ff8a5dd..0000000 --- a/server/jupyter_server/base/zmqhandlers.py +++ /dev/null @@ -1,346 +0,0 @@ -# coding: utf-8 -"""Tornado handlers for WebSocket <-> ZMQ sockets.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -import re -import struct -import sys -from urllib.parse import urlparse - -import tornado -from ipython_genutils.py3compat import cast_unicode - -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import date_default as json_default -from jupyter_client.jsonutil import extract_dates -from jupyter_client.session import Session -from tornado import ioloop -from tornado import web -from tornado.websocket import WebSocketHandler - -from .handlers import JupyterHandler - - -def serialize_binary_message(msg): - """serialize a message as a binary blob - - Header: - - 4 bytes: number of msg parts (nbufs) as 32b int - 4 * nbufs bytes: offset for each buffer as integer as 32b int - - Offsets are from the start of the buffer, including the header. - - Returns - ------- - The message serialized to bytes. - - """ - # don't modify msg or buffer list in-place - msg = msg.copy() - buffers = list(msg.pop("buffers")) - if sys.version_info < (3, 4): - buffers = [x.tobytes() for x in buffers] - bmsg = json.dumps(msg, default=json_default).encode("utf8") - buffers.insert(0, bmsg) - nbufs = len(buffers) - offsets = [4 * (nbufs + 1)] - for buf in buffers[:-1]: - offsets.append(offsets[-1] + len(buf)) - offsets_buf = struct.pack("!" + "I" * (nbufs + 1), nbufs, *offsets) - buffers.insert(0, offsets_buf) - return b"".join(buffers) - - -def deserialize_binary_message(bmsg): - """deserialize a message from a binary blog - - Header: - - 4 bytes: number of msg parts (nbufs) as 32b int - 4 * nbufs bytes: offset for each buffer as integer as 32b int - - Offsets are from the start of the buffer, including the header. - - Returns - ------- - message dictionary - """ - nbufs = struct.unpack("!i", bmsg[:4])[0] - offsets = list(struct.unpack("!" + "I" * nbufs, bmsg[4 : 4 * (nbufs + 1)])) - offsets.append(None) - bufs = [] - for start, stop in zip(offsets[:-1], offsets[1:]): - bufs.append(bmsg[start:stop]) - msg = json.loads(bufs[0].decode("utf8")) - msg["header"] = extract_dates(msg["header"]) - msg["parent_header"] = extract_dates(msg["parent_header"]) - msg["buffers"] = bufs[1:] - return msg - - -def serialize_msg_to_ws_v1(msg_or_list, channel, pack=None): - if pack: - msg_list = [ - pack(msg_or_list["header"]), - pack(msg_or_list["parent_header"]), - pack(msg_or_list["metadata"]), - pack(msg_or_list["content"]), - ] - else: - msg_list = msg_or_list - channel = channel.encode("utf-8") - offsets = [] - offsets.append(8 * (1 + 1 + len(msg_list) + 1)) - offsets.append(len(channel) + offsets[-1]) - for msg in msg_list: - offsets.append(len(msg) + offsets[-1]) - offset_number = len(offsets).to_bytes(8, byteorder="little") - offsets = [offset.to_bytes(8, byteorder="little") for offset in offsets] - bin_msg = b"".join([offset_number] + offsets + [channel] + msg_list) - return bin_msg - - -def deserialize_msg_from_ws_v1(ws_msg): - offset_number = int.from_bytes(ws_msg[:8], "little") - offsets = [ - int.from_bytes(ws_msg[8 * (i + 1) : 8 * (i + 2)], "little") for i in range(offset_number) - ] - channel = ws_msg[offsets[0] : offsets[1]].decode("utf-8") - msg_list = [ws_msg[offsets[i] : offsets[i + 1]] for i in range(1, offset_number - 1)] - return channel, msg_list - - -# ping interval for keeping websockets alive (30 seconds) -WS_PING_INTERVAL = 30000 - - -class WebSocketMixin(object): - """Mixin for common websocket options""" - - ping_callback = None - last_ping = 0 - last_pong = 0 - stream = None - - @property - def ping_interval(self): - """The interval for websocket keep-alive pings. - - Set ws_ping_interval = 0 to disable pings. - """ - return self.settings.get("ws_ping_interval", WS_PING_INTERVAL) - - @property - def ping_timeout(self): - """If no ping is received in this many milliseconds, - close the websocket connection (VPNs, etc. can fail to cleanly close ws connections). - Default is max of 3 pings or 30 seconds. - """ - return self.settings.get("ws_ping_timeout", max(3 * self.ping_interval, WS_PING_INTERVAL)) - - def check_origin(self, origin=None): - """Check Origin == Host or Access-Control-Allow-Origin. - - Tornado >= 4 calls this method automatically, raising 403 if it returns False. - """ - - if self.allow_origin == "*" or ( - hasattr(self, "skip_check_origin") and self.skip_check_origin() - ): - return True - - host = self.request.headers.get("Host") - if origin is None: - origin = self.get_origin() - - # If no origin or host header is provided, assume from script - if origin is None or host is None: - return True - - origin = origin.lower() - origin_host = urlparse(origin).netloc - - # OK if origin matches host - if origin_host == host: - return True - - # Check CORS headers - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(re.match(self.allow_origin_pat, origin)) - else: - # No CORS headers deny the request - allow = False - if not allow: - self.log.warning( - "Blocking Cross Origin WebSocket Attempt. Origin: %s, Host: %s", - origin, - host, - ) - return allow - - def clear_cookie(self, *args, **kwargs): - """meaningless for websockets""" - pass - - def open(self, *args, **kwargs): - self.log.debug("Opening websocket %s", self.request.path) - - # start the pinging - if self.ping_interval > 0: - loop = ioloop.IOLoop.current() - self.last_ping = loop.time() # Remember time of last ping - self.last_pong = self.last_ping - self.ping_callback = ioloop.PeriodicCallback( - self.send_ping, - self.ping_interval, - ) - self.ping_callback.start() - return super(WebSocketMixin, self).open(*args, **kwargs) - - def send_ping(self): - """send a ping to keep the websocket alive""" - if self.ws_connection is None and self.ping_callback is not None: - self.ping_callback.stop() - return - - if self.ws_connection.client_terminated: - self.close() - return - - # check for timeout on pong. Make sure that we really have sent a recent ping in - # case the machine with both server and client has been suspended since the last ping. - now = ioloop.IOLoop.current().time() - since_last_pong = 1e3 * (now - self.last_pong) - since_last_ping = 1e3 * (now - self.last_ping) - if since_last_ping < 2 * self.ping_interval and since_last_pong > self.ping_timeout: - self.log.warning("WebSocket ping timeout after %i ms.", since_last_pong) - self.close() - return - - self.ping(b"") - self.last_ping = now - - def on_pong(self, data): - self.last_pong = ioloop.IOLoop.current().time() - - -class ZMQStreamHandler(WebSocketMixin, WebSocketHandler): - - if tornado.version_info < (4, 1): - """Backport send_error from tornado 4.1 to 4.0""" - - def send_error(self, *args, **kwargs): - if self.stream is None: - super(WebSocketHandler, self).send_error(*args, **kwargs) - else: - # If we get an uncaught exception during the handshake, - # we have no choice but to abruptly close the connection. - # TODO: for uncaught exceptions after the handshake, - # we can close the connection more gracefully. - self.stream.close() - - def _reserialize_reply(self, msg_or_list, channel=None): - """Reserialize a reply message using JSON. - - msg_or_list can be an already-deserialized msg dict or the zmq buffer list. - If it is the zmq list, it will be deserialized with self.session. - - This takes the msg list from the ZMQ socket and serializes the result for the websocket. - This method should be used by self._on_zmq_reply to build messages that can - be sent back to the browser. - - """ - if isinstance(msg_or_list, dict): - # already unpacked - msg = msg_or_list - else: - idents, msg_list = self.session.feed_identities(msg_or_list) - msg = self.session.deserialize(msg_list) - if channel: - msg["channel"] = channel - if msg["buffers"]: - buf = serialize_binary_message(msg) - return buf - else: - smsg = json.dumps(msg, default=json_default) - return cast_unicode(smsg) - - def select_subprotocol(self, subprotocols): - preferred_protocol = self.settings.get("kernel_ws_protocol") - if preferred_protocol is None: - preferred_protocol = "v1.kernel.websocket.jupyter.org" - elif preferred_protocol == "": - preferred_protocol = None - selected_subprotocol = preferred_protocol if preferred_protocol in subprotocols else None - # None is the default, "legacy" protocol - return selected_subprotocol - - def _on_zmq_reply(self, stream, msg_list): - # Sometimes this gets triggered when the on_close method is scheduled in the - # eventloop but hasn't been called. - if self.ws_connection is None or stream.closed(): - self.log.warning("zmq message arrived on closed channel") - self.close() - return - channel = getattr(stream, "channel", None) - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - bin_msg = serialize_msg_to_ws_v1(msg_list, channel) - self.write_message(bin_msg, binary=True) - else: - try: - msg = self._reserialize_reply(msg_list, channel=channel) - except Exception: - self.log.critical("Malformed message: %r" % msg_list, exc_info=True) - else: - self.write_message(msg, binary=isinstance(msg, bytes)) - - -class AuthenticatedZMQStreamHandler(ZMQStreamHandler, JupyterHandler): - def set_default_headers(self): - """Undo the set_default_headers in JupyterHandler - - which doesn't make sense for websockets - """ - pass - - def pre_get(self): - """Run before finishing the GET request - - Extend this method to add logic that should fire before - the websocket finishes completing. - """ - # authenticate the request before opening the websocket - user = self.get_current_user() - if user is None: - self.log.warning("Couldn't authenticate WebSocket connection") - raise web.HTTPError(403) - - # authorize the user. - if not self.authorizer.is_authorized(self, user, "execute", "kernels"): - raise web.HTTPError(403) - - if self.get_argument("session_id", False): - self.session.session = cast_unicode(self.get_argument("session_id")) - else: - self.log.warning("No session ID specified") - - async def get(self, *args, **kwargs): - # pre_get can be a coroutine in subclasses - # assign and yield in two step to avoid tornado 3 issues - res = self.pre_get() - await res - res = super(AuthenticatedZMQStreamHandler, self).get(*args, **kwargs) - await res - - def initialize(self): - self.log.debug("Initializing websocket connection %s", self.request.path) - self.session = Session(config=self.config) - - def get_compression_options(self): - return self.settings.get("websocket_compression_options", None) diff --git a/server/jupyter_server/config_manager.py b/server/jupyter_server/config_manager.py deleted file mode 100644 index 933529a..0000000 --- a/server/jupyter_server/config_manager.py +++ /dev/null @@ -1,138 +0,0 @@ -# coding: utf-8 -"""Manager to read and modify config data in JSON files.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import copy -import errno -import glob -import io -import json -import os - -from six import PY3 -from traitlets.config import LoggingConfigurable -from traitlets.traitlets import Bool -from traitlets.traitlets import Unicode - - -def recursive_update(target, new): - """Recursively update one dictionary using another. - - None values will delete their keys. - """ - for k, v in new.items(): - if isinstance(v, dict): - if k not in target: - target[k] = {} - recursive_update(target[k], v) - if not target[k]: - # Prune empty subdicts - del target[k] - - elif v is None: - target.pop(k, None) - - else: - target[k] = v - - -def remove_defaults(data, defaults): - """Recursively remove items from dict that are already in defaults""" - # copy the iterator, since data will be modified - for key, value in list(data.items()): - if key in defaults: - if isinstance(value, dict): - remove_defaults(data[key], defaults[key]) - if not data[key]: # prune empty subdicts - del data[key] - else: - if value == defaults[key]: - del data[key] - - -class BaseJSONConfigManager(LoggingConfigurable): - """General JSON config manager - - Deals with persisting/storing config in a json file with optionally - default values in a {section_name}.d directory. - """ - - config_dir = Unicode(".") - read_directory = Bool(True) - - def ensure_config_dir_exists(self): - """Will try to create the config_dir directory.""" - try: - os.makedirs(self.config_dir, 0o755) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - def file_name(self, section_name): - """Returns the json filename for the section_name: {config_dir}/{section_name}.json""" - return os.path.join(self.config_dir, section_name + ".json") - - def directory(self, section_name): - """Returns the directory name for the section name: {config_dir}/{section_name}.d""" - return os.path.join(self.config_dir, section_name + ".d") - - def get(self, section_name, include_root=True): - """Retrieve the config data for the specified section. - - Returns the data as a dictionary, or an empty dictionary if the file - doesn't exist. - - When include_root is False, it will not read the root .json file, - effectively returning the default values. - """ - paths = [self.file_name(section_name)] if include_root else [] - if self.read_directory: - pattern = os.path.join(self.directory(section_name), "*.json") - # These json files should be processed first so that the - # {section_name}.json take precedence. - # The idea behind this is that installing a Python package may - # put a json file somewhere in the a .d directory, while the - # .json file is probably a user configuration. - paths = sorted(glob.glob(pattern)) + paths - self.log.debug( - "Paths used for configuration of %s: \n\t%s", - section_name, - "\n\t".join(paths), - ) - data = {} - for path in paths: - if os.path.isfile(path): - with io.open(path, encoding="utf-8") as f: - recursive_update(data, json.load(f)) - return data - - def set(self, section_name, data): - """Store the given config data.""" - filename = self.file_name(section_name) - self.ensure_config_dir_exists() - - if self.read_directory: - # we will modify data in place, so make a copy - data = copy.deepcopy(data) - defaults = self.get(section_name, include_root=False) - remove_defaults(data, defaults) - - # Generate the JSON up front, since it could raise an exception, - # in order to avoid writing half-finished corrupted data to disk. - json_content = json.dumps(data, indent=2) - if PY3: - f = io.open(filename, "w", encoding="utf-8") - else: - f = open(filename, "wb") - with f: - f.write(json_content) - - def update(self, section_name, new_data): - """Modify the config section by recursively updating it with new_data. - - Returns the modified config data as a dictionary. - """ - data = self.get(section_name) - recursive_update(data, new_data) - self.set(section_name, data) - return data diff --git a/server/jupyter_server/conftest.py b/server/jupyter_server/conftest.py deleted file mode 100644 index e1a9fe0..0000000 --- a/server/jupyter_server/conftest.py +++ /dev/null @@ -1,31 +0,0 @@ -import pytest - - -pytest_plugins = ["jupyter_server.pytest_plugin"] - - -def pytest_addoption(parser): - parser.addoption( - "--integration_tests", - default=False, - type=bool, - help="only run tests with the 'integration_test' pytest mark.", - ) - - -def pytest_configure(config): - # register an additional marker - config.addinivalue_line("markers", "integration_test") - - -def pytest_runtest_setup(item): - is_integration_test = any(mark for mark in item.iter_markers(name="integration_test")) - - if item.config.getoption("--integration_tests") is True: - if not is_integration_test: - pytest.skip("Only running tests marked as 'integration_test'.") - else: - if is_integration_test: - pytest.skip( - "Skipping this test because it's marked 'integration_test'. Run integration tests using the `--integration_tests` flag." - ) diff --git a/server/jupyter_server/extension/__init__.py b/server/jupyter_server/extension/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/extension/application.py b/server/jupyter_server/extension/application.py deleted file mode 100644 index ea18d68..0000000 --- a/server/jupyter_server/extension/application.py +++ /dev/null @@ -1,583 +0,0 @@ -import logging -import re -import sys - -from jinja2 import Environment -from jinja2 import FileSystemLoader -from jupyter_core.application import JupyterApp -from jupyter_core.application import NoStart -from tornado.log import LogFormatter -from tornado.web import RedirectHandler -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import HasTraits -from traitlets import List -from traitlets import Unicode -from traitlets.config import Config - -from .handler import ExtensionHandlerMixin -from jupyter_server.serverapp import ServerApp -from jupyter_server.transutils import _i18n -from jupyter_server.utils import is_namespace_package -from jupyter_server.utils import url_path_join - -# ----------------------------------------------------------------------------- -# Util functions and classes. -# ----------------------------------------------------------------------------- - - -def _preparse_for_subcommand(Application, argv): - """Preparse command line to look for subcommands.""" - # Read in arguments from command line. - if len(argv) == 0: - return - - # Find any subcommands. - if Application.subcommands and len(argv) > 0: - # we have subcommands, and one may have been specified - subc, subargv = argv[0], argv[1:] - if re.match(r"^\w(\-?\w)*$", subc) and subc in Application.subcommands: - # it's a subcommand, and *not* a flag or class parameter - app = Application() - app.initialize_subcommand(subc, subargv) - return app.subapp - - -def _preparse_for_stopping_flags(Application, argv): - """Looks for 'help', 'version', and 'generate-config; commands - in command line. If found, raises the help and version of - current Application. - - This is useful for traitlets applications that have to parse - the command line multiple times, but want to control when - when 'help' and 'version' is raised. - """ - # Arguments after a '--' argument are for the script IPython may be - # about to run, not IPython iteslf. For arguments parsed here (help and - # version), we want to only search the arguments up to the first - # occurrence of '--', which we're calling interpreted_argv. - try: - interpreted_argv = argv[: argv.index("--")] - except ValueError: - interpreted_argv = argv - - # Catch any help calls. - if any(x in interpreted_argv for x in ("-h", "--help-all", "--help")): - app = Application() - app.print_help("--help-all" in interpreted_argv) - app.exit(0) - - # Catch version commands - if "--version" in interpreted_argv or "-V" in interpreted_argv: - app = Application() - app.print_version() - app.exit(0) - - # Catch generate-config commands. - if "--generate-config" in interpreted_argv: - app = Application() - app.write_default_config() - app.exit(0) - - -class ExtensionAppJinjaMixin(HasTraits): - """Use Jinja templates for HTML templates on top of an ExtensionApp.""" - - jinja2_options = Dict( - help=_i18n( - """Options to pass to the jinja2 environment for this - """ - ) - ).tag(config=True) - - def _prepare_templates(self): - # Get templates defined in a subclass. - self.initialize_templates() - # Add templates to web app settings if extension has templates. - if len(self.template_paths) > 0: - self.settings.update({"{}_template_paths".format(self.name): self.template_paths}) - - # Create a jinja environment for logging html templates. - self.jinja2_env = Environment( - loader=FileSystemLoader(self.template_paths), - extensions=["jinja2.ext.i18n"], - autoescape=True, - **self.jinja2_options - ) - - # Add the jinja2 environment for this extension to the tornado settings. - self.settings.update({"{}_jinja2_env".format(self.name): self.jinja2_env}) - - -# ----------------------------------------------------------------------------- -# ExtensionApp -# ----------------------------------------------------------------------------- - - -class JupyterServerExtensionException(Exception): - """Exception class for raising for Server extensions errors.""" - - -# ----------------------------------------------------------------------------- -# ExtensionApp -# ----------------------------------------------------------------------------- - - -class ExtensionApp(JupyterApp): - """Base class for configurable Jupyter Server Extension Applications. - - ExtensionApp subclasses can be initialized two ways: - 1. Extension is listed as a jpserver_extension, and ServerApp calls - its load_jupyter_server_extension classmethod. This is the - classic way of loading a server extension. - 2. Extension is launched directly by calling its `launch_instance` - class method. This method can be set as a entry_point in - the extensions setup.py - """ - - # Subclasses should override this trait. Tells the server if - # this extension allows other other extensions to be loaded - # side-by-side when launched directly. - load_other_extensions = True - - # A useful class property that subclasses can override to - # configure the underlying Jupyter Server when this extension - # is launched directly (using its `launch_instance` method). - serverapp_config = {} - - # Some subclasses will likely override this trait to flip - # the default value to False if they don't offer a browser - # based frontend. - open_browser = Bool( - help="""Whether to open in a browser after starting. - The specific browser used is platform dependent and - determined by the python standard library `webbrowser` - module, unless it is overridden using the --browser - (ServerApp.browser) configuration option. - """ - ).tag(config=True) - - @default("open_browser") - def _default_open_browser(self): - return self.serverapp.config["ServerApp"].get("open_browser", True) - - # The extension name used to name the jupyter config - # file, jupyter_{name}_config. - # This should also match the jupyter subcommand used to launch - # this extension from the CLI, e.g. `jupyter {name}`. - name = None - - @classmethod - def get_extension_package(cls): - parts = cls.__module__.split(".") - if is_namespace_package(parts[0]): - # in this case the package name is `.`. - return ".".join(parts[0:2]) - return parts[0] - - @classmethod - def get_extension_point(cls): - return cls.__module__ - - # Extension URL sets the default landing page for this extension. - extension_url = "/" - - default_url = Unicode().tag(config=True) - - @default("default_url") - def _default_url(https://github.com/self): - return self.extension_url - - file_url_prefix = Unicode("notebooks") - - # Is this linked to a serverapp yet? - _linked = Bool(False) - - # Extension can configure the ServerApp from the command-line - classes = [ - ServerApp, - ] - - # A ServerApp is not defined yet, but will be initialized below. - serverapp = None - - _log_formatter_cls = LogFormatter - - @default("log_level") - def _default_log_level(self): - return logging.INFO - - @default("log_format") - def _default_log_format(self): - """override default log format to include date & time""" - return ( - "%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s]%(end_color)s %(message)s" - ) - - static_url_prefix = Unicode( - help="""Url where the static assets for the extension are served.""" - ).tag(config=True) - - @default("static_url_prefix") - def _default_static_url_prefix(self): - static_url = "static/{name}/".format(name=self.name) - return url_path_join(self.serverapp.base_url, static_url) - - static_paths = List( - Unicode(), - help="""paths to search for serving static files. - - This allows adding javascript/css to be available from the notebook server machine, - or overriding individual files in the IPython - """, - ).tag(config=True) - - template_paths = List( - Unicode(), - help=_i18n( - """Paths to search for serving jinja templates. - - Can be used to override templates from notebook.templates.""" - ), - ).tag(config=True) - - settings = Dict(help=_i18n("""Settings that will passed to the server.""")).tag(config=True) - - handlers = List(help=_i18n("""Handlers appended to the server.""")).tag(config=True) - - def _config_file_name_default(self): - """The default config file name.""" - if not self.name: - return "" - return "jupyter_{}_config".format(self.name.replace("-", "_")) - - def initialize_settings(self): - """Override this method to add handling of settings.""" - pass - - def initialize_handlers(self): - """Override this method to append handlers to a Jupyter Server.""" - pass - - def initialize_templates(self): - """Override this method to add handling of template files.""" - pass - - def _prepare_config(self): - """Builds a Config object from the extension's traits and passes - the object to the webapp's settings as `_config`. - """ - traits = self.class_own_traits().keys() - self.extension_config = Config({t: getattr(self, t) for t in traits}) - self.settings["{}_config".format(self.name)] = self.extension_config - - def _prepare_settings(self): - # Make webapp settings accessible to initialize_settings method - webapp = self.serverapp.web_app - self.settings.update(**webapp.settings) - - # Add static and template paths to settings. - self.settings.update( - { - "{}_static_paths".format(self.name): self.static_paths, - "{}".format(self.name): self, - } - ) - - # Get setting defined by subclass using initialize_settings method. - self.initialize_settings() - - # Update server settings with extension settings. - webapp.settings.update(**self.settings) - - def _prepare_handlers(self): - webapp = self.serverapp.web_app - - # Get handlers defined by extension subclass. - self.initialize_handlers() - - # prepend base_url onto the patterns that we match - new_handlers = [] - for handler_items in self.handlers: - # Build url pattern including base_url - pattern = url_path_join(webapp.settings["base_url"], handler_items[0]) - handler = handler_items[1] - - # Get handler kwargs, if given - kwargs = {} - if issubclass(handler, ExtensionHandlerMixin): - kwargs["name"] = self.name - - try: - kwargs.update(handler_items[2]) - except IndexError: - pass - - new_handler = (pattern, handler, kwargs) - new_handlers.append(new_handler) - - # Add static endpoint for this extension, if static paths are given. - if len(self.static_paths) > 0: - # Append the extension's static directory to server handlers. - static_url = url_path_join(self.static_url_prefix, "(.*)") - - # Construct handler. - handler = ( - static_url, - webapp.settings["static_handler_class"], - {"path": self.static_paths}, - ) - new_handlers.append(handler) - - webapp.add_handlers(".*$", new_handlers) - - def _prepare_templates(self): - # Add templates to web app settings if extension has templates. - if len(self.template_paths) > 0: - self.settings.update({"{}_template_paths".format(self.name): self.template_paths}) - self.initialize_templates() - - def _jupyter_server_config(self): - base_config = { - "ServerApp": { - "default_url": self.default_url, - "open_browser": self.open_browser, - "file_url_prefix": self.file_url_prefix, - } - } - base_config["ServerApp"].update(self.serverapp_config) - return base_config - - def _link_jupyter_server_extension(self, serverapp): - """Link the ExtensionApp to an initialized ServerApp. - - The ServerApp is stored as an attribute and config - is exchanged between ServerApp and `self` in case - the command line contains traits for the ExtensionApp - or the ExtensionApp's config files have server - settings. - - Note, the ServerApp has not initialized the Tornado - Web Application yet, so do not try to affect the - `web_app` attribute. - """ - self.serverapp = serverapp - # Load config from an ExtensionApp's config files. - self.load_config_file() - # ServerApp's config might have picked up - # config for the ExtensionApp. We call - # update_config to update ExtensionApp's - # traits with these values found in ServerApp's - # config. - # ServerApp config ---> ExtensionApp traits - self.update_config(self.serverapp.config) - # Use ExtensionApp's CLI parser to find any extra - # args that passed through ServerApp and - # now belong to ExtensionApp. - self.parse_command_line(self.serverapp.extra_args) - # If any config should be passed upstream to the - # ServerApp, do it here. - # i.e. ServerApp traits <--- ExtensionApp config - self.serverapp.update_config(self.config) - # Acknowledge that this extension has been linked. - self._linked = True - - def initialize(self): - """Initialize the extension app. The - corresponding server app and webapp should already - be initialized by this step. - - 1) Appends Handlers to the ServerApp, - 2) Passes config and settings from ExtensionApp - to the Tornado web application - 3) Points Tornado Webapp to templates and - static assets. - """ - if not self.serverapp: - msg = ( - "This extension has no attribute `serverapp`. " - "Try calling `.link_to_serverapp()` before calling " - "`.initialize()`." - ) - raise JupyterServerExtensionException(msg) - - self._prepare_config() - self._prepare_templates() - self._prepare_settings() - self._prepare_handlers() - - def start(self): - """Start the underlying Jupyter server. - - Server should be started after extension is initialized. - """ - super(ExtensionApp, self).start() - # Start the server. - self.serverapp.start() - - async def stop_extension(self): - """Cleanup any resources managed by this extension.""" - - def stop(self): - """Stop the underlying Jupyter server.""" - self.serverapp.stop() - self.serverapp.clear_instance() - - @classmethod - def _load_jupyter_server_extension(cls, serverapp): - """Initialize and configure this extension, then add the extension's - settings and handlers to the server's web application. - """ - extension_manager = serverapp.extension_manager - try: - # Get loaded extension from serverapp. - point = extension_manager.extension_points[cls.name] - extension = point.app - except KeyError: - extension = cls() - extension._link_jupyter_server_extension(serverapp) - extension.initialize() - return extension - - @classmethod - def load_classic_server_extension(cls, serverapp): - """Enables extension to be loaded as classic Notebook (jupyter/notebook) extension.""" - extension = cls() - extension.serverapp = serverapp - extension.load_config_file() - extension.update_config(serverapp.config) - extension.parse_command_line(serverapp.extra_args) - # Add redirects to get favicons from old locations in the classic notebook server - extension.handlers.extend( - [ - ( - r"/static/favicons/favicon.ico", - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/favicon.ico")}, - ), - ( - r"/static/favicons/favicon-busy-1.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, "static/base/images/favicon-busy-1.ico" - ) - }, - ), - ( - r"/static/favicons/favicon-busy-2.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, "static/base/images/favicon-busy-2.ico" - ) - }, - ), - ( - r"/static/favicons/favicon-busy-3.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, "static/base/images/favicon-busy-3.ico" - ) - }, - ), - ( - r"/static/favicons/favicon-file.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, "static/base/images/favicon-file.ico" - ) - }, - ), - ( - r"/static/favicons/favicon-notebook.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, - "static/base/images/favicon-notebook.ico", - ) - }, - ), - ( - r"/static/favicons/favicon-terminal.ico", - RedirectHandler, - { - "url": url_path_join( - serverapp.base_url, - "static/base/images/favicon-terminal.ico", - ) - }, - ), - ( - r"/static/logo/logo.png", - RedirectHandler, - {"url": url_path_join(serverapp.base_url, "static/base/images/logo.png")}, - ), - ] - ) - extension.initialize() - - @classmethod - def initialize_server(cls, argv=[], load_other_extensions=True, **kwargs): - """Creates an instance of ServerApp and explicitly sets - this extension to enabled=True (i.e. superceding disabling - found in other config from files). - - The `launch_instance` method uses this method to initialize - and start a server. - """ - jpserver_extensions = {cls.get_extension_package(): True} - find_extensions = cls.load_other_extensions - if "jpserver_extensions" in cls.serverapp_config: - jpserver_extensions.update(cls.serverapp_config["jpserver_extensions"]) - cls.serverapp_config["jpserver_extensions"] = jpserver_extensions - find_extensions = False - serverapp = ServerApp.instance(jpserver_extensions=jpserver_extensions, **kwargs) - serverapp.aliases.update(cls.aliases) - serverapp.initialize( - argv=argv, - starter_extension=cls.name, - find_extensions=find_extensions, - ) - return serverapp - - @classmethod - def launch_instance(cls, argv=None, **kwargs): - """Launch the extension like an application. Initializes+configs a stock server - and appends the extension to the server. Then starts the server and routes to - extension's landing page. - """ - # Handle arguments. - if argv is None: - args = sys.argv[1:] # slice out extension config. - else: - args = argv - - # Handle all "stops" that could happen before - # continuing to launch a server+extension. - subapp = _preparse_for_subcommand(cls, args) - if subapp: - subapp.start() - return - - # Check for help, version, and generate-config arguments - # before initializing server to make sure these - # arguments trigger actions from the extension not the server. - _preparse_for_stopping_flags(cls, args) - serverapp = cls.initialize_server(argv=args) - - # Log if extension is blocking other extensions from loading. - if not cls.load_other_extensions: - serverapp.log.info( - "{ext_name} is running without loading " - "other extensions.".format(ext_name=cls.name) - ) - # Start the server. - try: - serverapp.start() - except NoStart: - pass diff --git a/server/jupyter_server/extension/config.py b/server/jupyter_server/extension/config.py deleted file mode 100644 index 8fb6cec..0000000 --- a/server/jupyter_server/extension/config.py +++ /dev/null @@ -1,33 +0,0 @@ -from jupyter_server.services.config.manager import ConfigManager - - -DEFAULT_SECTION_NAME = "jupyter_server_config" - - -class ExtensionConfigManager(ConfigManager): - """A manager class to interface with Jupyter Server Extension config - found in a `config.d` folder. It is assumed that all configuration - files in this directory are JSON files. - """ - - def get_jpserver_extensions(self, section_name=DEFAULT_SECTION_NAME): - """Return the jpserver_extensions field from all - config files found.""" - data = self.get(section_name) - return data.get("ServerApp", {}).get("jpserver_extensions", {}) - - def enabled(self, name, section_name=DEFAULT_SECTION_NAME, include_root=True): - """Is the extension enabled?""" - extensions = self.get_jpserver_extensions(section_name) - try: - return extensions[name] - except KeyError: - return False - - def enable(self, name): - data = {"ServerApp": {"jpserver_extensions": {name: True}}} - self.update(name, data) - - def disable(self, name): - data = {"ServerApp": {"jpserver_extensions": {name: False}}} - self.update(name, data) diff --git a/server/jupyter_server/extension/handler.py b/server/jupyter_server/extension/handler.py deleted file mode 100644 index be257a4..0000000 --- a/server/jupyter_server/extension/handler.py +++ /dev/null @@ -1,119 +0,0 @@ -from jinja2.exceptions import TemplateNotFound - -from jupyter_server.base.handlers import FileFindHandler - - -class ExtensionHandlerJinjaMixin: - """Mixin class for ExtensionApp handlers that use jinja templating for - template rendering. - """ - - def get_template(self, name): - """Return the jinja template object for a given name""" - try: - env = "{}_jinja2_env".format(self.name) - return self.settings[env].get_template(name) - except TemplateNotFound: - return super().get_template(name) - - -class ExtensionHandlerMixin: - """Base class for Jupyter server extension handlers. - - Subclasses can serve static files behind a namespaced - endpoint: "/static//" - - This allows multiple extensions to serve static files under - their own namespace and avoid intercepting requests for - other extensions. - """ - - def initialize(self, name): - self.name = name - - @property - def extensionapp(self): - return self.settings[self.name] - - @property - def serverapp(self): - key = "serverapp" - return self.settings[key] - - @property - def log(self): - if not hasattr(self, "name"): - return super().log - # Attempt to pull the ExtensionApp's log, otherwise fall back to ServerApp. - try: - return self.extensionapp.log - except AttributeError: - return self.serverapp.log - - @property - def config(self): - return self.settings["{}_config".format(self.name)] - - @property - def server_config(self): - return self.settings["config"] - - @property - def base_url(https://github.com/self): - return self.settings.get("base_url", "/") - - @property - def static_url_prefix(self): - return self.extensionapp.static_url_prefix - - @property - def static_path(self): - return self.settings["{}_static_paths".format(self.name)] - - def static_url(https://github.com/self,%20path,%20include_host=None,%20**kwargs): - """Returns a static URL for the given relative static file path. - This method requires you set the ``{name}_static_path`` - setting in your extension (which specifies the root directory - of your static files). - This method returns a versioned url (by default appending - ``?v=``), which allows the static files to be - cached indefinitely. This can be disabled by passing - ``include_version=False`` (in the default implementation; - other static file implementations are not required to support - this, but they may support other options). - By default this method returns URLs relative to the current - host, but if ``include_host`` is true the URL returned will be - absolute. If this handler has an ``include_host`` attribute, - that value will be used as the default for all `static_url` - calls that do not pass ``include_host`` as a keyword argument. - """ - key = "{}_static_paths".format(self.name) - try: - self.require_setting(key, "static_url") - except Exception as e: - if key in self.settings: - raise Exception( - "This extension doesn't have any static paths listed. Check that the " - "extension's `static_paths` trait is set." - ) from e - else: - raise e - - get_url = self.settings.get("static_handler_class", FileFindHandler).make_static_url - - if include_host is None: - include_host = getattr(self, "include_host", False) - - if include_host: - base = self.request.protocol + "://" + self.request.host - else: - base = "" - - # Hijack settings dict to send extension templates to extension - # static directory. - settings = { - "static_path": self.static_path, - "static_url_prefix": self.static_url_prefix, - } - - return base + get_url(https://github.com/settings,%20path,%20**kwargs) diff --git a/server/jupyter_server/extension/manager.py b/server/jupyter_server/extension/manager.py deleted file mode 100644 index 2f92e78..0000000 --- a/server/jupyter_server/extension/manager.py +++ /dev/null @@ -1,401 +0,0 @@ -import importlib -import sys -import traceback - -from tornado.gen import multi -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import HasTraits -from traitlets import Instance -from traitlets import observe -from traitlets import Unicode -from traitlets import validate as validate_trait -from traitlets.config import LoggingConfigurable - -from .config import ExtensionConfigManager -from .utils import ExtensionMetadataError -from .utils import ExtensionModuleNotFound -from .utils import get_loader -from .utils import get_metadata - - -class ExtensionPoint(HasTraits): - """A simple API for connecting to a Jupyter Server extension - point defined by metadata and importable from a Python package. - """ - - _linked = Bool(False) - _app = Any(None, allow_none=True) - - metadata = Dict() - - @validate_trait("metadata") - def _valid_metadata(self, proposed): - metadata = proposed["value"] - # Verify that the metadata has a "name" key. - try: - self._module_name = metadata["module"] - except KeyError: - raise ExtensionMetadataError( - "There is no 'module' key in the extension's " "metadata packet." - ) - - try: - self._module = importlib.import_module(self._module_name) - except ImportError: - raise ExtensionModuleNotFound( - "The submodule '{}' could not be found. Are you " - "sure the extension is installed?".format(self._module_name) - ) - # If the metadata includes an ExtensionApp, create an instance. - if "app" in metadata: - self._app = metadata["app"]() - return metadata - - @property - def linked(self): - """Has this extension point been linked to the server. - - Will pull from ExtensionApp's trait, if this point - is an instance of ExtensionApp. - """ - if self.app: - return self.app._linked - return self._linked - - @property - def app(self): - """If the metadata includes an `app` field""" - return self._app - - @property - def config(self): - """Return any configuration provided by this extension point.""" - if self.app: - return self.app._jupyter_server_config() - # At some point, we might want to add logic to load config from - # disk when extensions don't use ExtensionApp. - else: - return {} - - @property - def module_name(self): - """Name of the Python package module where the extension's - _load_jupyter_server_extension can be found. - """ - return self._module_name - - @property - def name(self): - """Name of the extension. - - If it's not provided in the metadata, `name` is set - to the extensions' module name. - """ - if self.app: - return self.app.name - return self.metadata.get("name", self.module_name) - - @property - def module(self): - """The imported module (using importlib.import_module)""" - return self._module - - def _get_linker(self): - if self.app: - linker = self.app._link_jupyter_server_extension - else: - linker = getattr( - self.module, - # Search for a _link_jupyter_extension - "_link_jupyter_server_extension", - # Otherwise return a dummy function. - lambda serverapp: None, - ) - return linker - - def _get_loader(self): - loc = self.app - if not loc: - loc = self.module - loader = get_loader(loc) - return loader - - def validate(self): - """Check that both a linker and loader exists.""" - try: - self._get_linker() - self._get_loader() - except Exception: - return False - else: - return True - - def link(self, serverapp): - """Link the extension to a Jupyter ServerApp object. - - This looks for a `_link_jupyter_server_extension` function - in the extension's module or ExtensionApp class. - """ - if not self.linked: - linker = self._get_linker() - linker(serverapp) - # Store this extension as already linked. - self._linked = True - - def load(self, serverapp): - """Load the extension in a Jupyter ServerApp object. - - This looks for a `_load_jupyter_server_extension` function - in the extension's module or ExtensionApp class. - """ - loader = self._get_loader() - return loader(serverapp) - - -class ExtensionPackage(HasTraits): - """An API for interfacing with a Jupyter Server extension package. - - Usage: - - ext_name = "my_extensions" - extpkg = ExtensionPackage(name=ext_name) - """ - - name = Unicode(help="Name of the an importable Python package.") - enabled = Bool(False).tag(config=True) - - def __init__(self, *args, **kwargs): - # Store extension points that have been linked. - self._linked_points = {} - super().__init__(*args, **kwargs) - - _linked_points = {} - - @validate_trait("name") - def _validate_name(self, proposed): - name = proposed["value"] - self._extension_points = {} - try: - self._module, self._metadata = get_metadata(name) - except ImportError: - raise ExtensionModuleNotFound( - "The module '{name}' could not be found. Are you " - "sure the extension is installed?".format(name=name) - ) - # Create extension point interfaces for each extension path. - for m in self._metadata: - point = ExtensionPoint(metadata=m) - self._extension_points[point.name] = point - return name - - @property - def module(self): - """Extension metadata loaded from the extension package.""" - return self._module - - @property - def version(self): - """Get the version of this package, if it's given. Otherwise, return an empty string""" - return getattr(self._module, "__version__", "") - - @property - def metadata(self): - """Extension metadata loaded from the extension package.""" - return self._metadata - - @property - def extension_points(self): - """A dictionary of extension points.""" - return self._extension_points - - def validate(self): - """Validate all extension points in this package.""" - for extension in self.extension_points.values(): - if not extension.validate(): - return False - return True - - def link_point(self, point_name, serverapp): - linked = self._linked_points.get(point_name, False) - if not linked: - point = self.extension_points[point_name] - point.link(serverapp) - - def load_point(self, point_name, serverapp): - point = self.extension_points[point_name] - return point.load(serverapp) - - def link_all_points(self, serverapp): - for point_name in self.extension_points: - self.link_point(point_name, serverapp) - - def load_all_points(self, serverapp): - return [self.load_point(point_name, serverapp) for point_name in self.extension_points] - - -class ExtensionManager(LoggingConfigurable): - """High level interface for findind, validating, - linking, loading, and managing Jupyter Server extensions. - - Usage: - m = ExtensionManager(config_manager=...) - """ - - config_manager = Instance(ExtensionConfigManager, allow_none=True) - - serverapp = Any() # Use Any to avoid circular import of Instance(ServerApp) - - @default("config_manager") - def _load_default_config_manager(self): - config_manager = ExtensionConfigManager() - self._load_config_manager(config_manager) - return config_manager - - @observe("config_manager") - def _config_manager_changed(self, change): - if change.new: - self._load_config_manager(change.new) - - # The `extensions` attribute provides a dictionary - # with extension (package) names mapped to their ExtensionPackage interface - # (see above). This manager simplifies the interaction between the - # ServerApp and the extensions being appended. - extensions = Dict( - help=""" - Dictionary with extension package names as keys - and ExtensionPackage objects as values. - """ - ) - - @property - def sorted_extensions(self): - """Returns an extensions dictionary, sorted alphabetically.""" - return dict(sorted(self.extensions.items())) - - # The `_linked_extensions` attribute tracks when each extension - # has been successfully linked to a ServerApp. This helps prevent - # extensions from being re-linked recursively unintentionally if another - # extension attempts to link extensions again. - linked_extensions = Dict( - help=""" - Dictionary with extension names as keys - - values are True if the extension is linked, False if not. - """ - ) - - @property - def extension_apps(self): - """Return mapping of extension names and sets of ExtensionApp objects.""" - return { - name: {point.app for point in extension.extension_points.values() if point.app} - for name, extension in self.extensions.items() - } - - @property - def extension_points(self): - """Return mapping of extension point names and ExtensionPoint objects.""" - return { - name: point - for value in self.extensions.values() - for name, point in value.extension_points.items() - } - - def from_config_manager(self, config_manager): - """Add extensions found by an ExtensionConfigManager""" - # load triggered via config_manager trait observer - self.config_manager = config_manager - - def _load_config_manager(self, config_manager): - """Actually load our config manager""" - jpserver_extensions = config_manager.get_jpserver_extensions() - self.from_jpserver_extensions(jpserver_extensions) - - def from_jpserver_extensions(self, jpserver_extensions): - """Add extensions from 'jpserver_extensions'-like dictionary.""" - for name, enabled in jpserver_extensions.items(): - self.add_extension(name, enabled=enabled) - - def add_extension(self, extension_name, enabled=False): - """Try to add extension to manager, return True if successful. - Otherwise, return False. - """ - try: - extpkg = ExtensionPackage(name=extension_name, enabled=enabled) - self.extensions[extension_name] = extpkg - return True - # Raise a warning if the extension cannot be loaded. - except Exception as e: - if self.serverapp.reraise_server_extension_failures: - raise - self.log.warning(e) - return False - - def link_extension(self, name): - linked = self.linked_extensions.get(name, False) - extension = self.extensions[name] - if not linked and extension.enabled: - try: - # Link extension and store links - extension.link_all_points(self.serverapp) - self.linked_extensions[name] = True - self.log.info("{name} | extension was successfully linked.".format(name=name)) - except Exception as e: - if self.serverapp.reraise_server_extension_failures: - raise - self.log.warning(e) - - def load_extension(self, name): - extension = self.extensions.get(name) - - if extension.enabled: - try: - extension.load_all_points(self.serverapp) - except Exception as e: - if self.serverapp.reraise_server_extension_failures: - raise - self.log.debug("".join(traceback.format_exception(*sys.exc_info()))) - self.log.warning( - "{name} | extension failed loading with message: {error}".format( - name=name, error=str(e) - ) - ) - else: - self.log.info("{name} | extension was successfully loaded.".format(name=name)) - - async def stop_extension(self, name, apps): - """Call the shutdown hooks in the specified apps.""" - for app in apps: - self.log.debug('{} | extension app "{}" stopping'.format(name, app.name)) - await app.stop_extension() - self.log.debug('{} | extension app "{}" stopped'.format(name, app.name)) - - def link_all_extensions(self): - """Link all enabled extensions - to an instance of ServerApp - """ - # Sort the extension names to enforce deterministic linking - # order. - for name in self.sorted_extensions.keys(): - self.link_extension(name) - - def load_all_extensions(self): - """Load all enabled extensions and append them to - the parent ServerApp. - """ - # Sort the extension names to enforce deterministic loading - # order. - for name in self.sorted_extensions.keys(): - self.load_extension(name) - - async def stop_all_extensions(self): - """Call the shutdown hooks in all extensions.""" - await multi( - [ - self.stop_extension(name, apps) - for name, apps in sorted(dict(self.extension_apps).items()) - ] - ) diff --git a/server/jupyter_server/extension/serverextension.py b/server/jupyter_server/extension/serverextension.py deleted file mode 100644 index 31a8c56..0000000 --- a/server/jupyter_server/extension/serverextension.py +++ /dev/null @@ -1,384 +0,0 @@ -# coding: utf-8 -"""Utilities for installing extensions""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import sys - -from jupyter_core.application import JupyterApp -from jupyter_core.paths import ENV_CONFIG_PATH -from jupyter_core.paths import jupyter_config_dir -from jupyter_core.paths import SYSTEM_CONFIG_PATH -from tornado.log import LogFormatter -from traitlets import Bool - -from jupyter_server._version import __version__ -from jupyter_server.extension.config import ExtensionConfigManager -from jupyter_server.extension.manager import ExtensionManager -from jupyter_server.extension.manager import ExtensionPackage - - -def _get_config_dir(user=False, sys_prefix=False): - """Get the location of config files for the current context - - Returns the string to the environment - - Parameters - ---------- - user : bool [default: False] - Get the user's .jupyter config directory - sys_prefix : bool [default: False] - Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter - """ - if user and sys_prefix: - sys_prefix = False - if user: - extdir = jupyter_config_dir() - elif sys_prefix: - extdir = ENV_CONFIG_PATH[0] - else: - extdir = SYSTEM_CONFIG_PATH[0] - return extdir - - -def _get_extmanager_for_context(write_dir="jupyter_server_config.d", user=False, sys_prefix=False): - """Get an extension manager pointing at the current context - - Returns the path to the current context and an ExtensionManager object. - - Parameters - ---------- - write_dir : str [default: 'jupyter_server_config.d'] - Name of config directory to write extension config. - user : bool [default: False] - Get the user's .jupyter config directory - sys_prefix : bool [default: False] - Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter - """ - config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix) - config_manager = ExtensionConfigManager( - read_config_path=[config_dir], - write_config_dir=os.path.join(config_dir, write_dir), - ) - extension_manager = ExtensionManager( - config_manager=config_manager, - ) - return config_dir, extension_manager - - -class ArgumentConflict(ValueError): - pass - - -_base_flags = {} -_base_flags.update(JupyterApp.flags) -_base_flags.pop("y", None) -_base_flags.pop("generate-config", None) -_base_flags.update( - { - "user": ( - { - "BaseExtensionApp": { - "user": True, - } - }, - "Apply the operation only for the given user", - ), - "system": ( - { - "BaseExtensionApp": { - "user": False, - "sys_prefix": False, - } - }, - "Apply the operation system-wide", - ), - "sys-prefix": ( - { - "BaseExtensionApp": { - "sys_prefix": True, - } - }, - "Use sys.prefix as the prefix for installing extensions (for environments, packaging)", - ), - "py": ( - { - "BaseExtensionApp": { - "python": True, - } - }, - "Install from a Python package", - ), - } -) -_base_flags["python"] = _base_flags["py"] - -_base_aliases = {} -_base_aliases.update(JupyterApp.aliases) - - -class BaseExtensionApp(JupyterApp): - """Base extension installer app""" - - _log_formatter_cls = LogFormatter - flags = _base_flags - aliases = _base_aliases - version = __version__ - - user = Bool(False, config=True, help="Whether to do a user install") - sys_prefix = Bool(True, config=True, help="Use the sys.prefix as the prefix") - python = Bool(False, config=True, help="Install from a Python package") - - def _log_format_default(self): - """A default format for messages""" - return "%(message)s" - - @property - def config_dir(self): - return _get_config_dir(user=self.user, sys_prefix=self.sys_prefix) - - -# Constants for pretty print extension listing function. -# Window doesn't support coloring in the commandline -GREEN_ENABLED = "\033[32menabled\033[0m" if os.name != "nt" else "enabled" -RED_DISABLED = "\033[31mdisabled\033[0m" if os.name != "nt" else "disabled" -GREEN_OK = "\033[32mOK\033[0m" if os.name != "nt" else "ok" -RED_X = "\033[31m X\033[0m" if os.name != "nt" else " X" - -# ------------------------------------------------------------------------------ -# Public API -# ------------------------------------------------------------------------------ - - -def toggle_server_extension_python( - import_name, enabled=None, parent=None, user=False, sys_prefix=True -): - """Toggle the boolean setting for a given server extension - in a Jupyter config file. - """ - sys_prefix = False if user else sys_prefix - config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix) - manager = ExtensionConfigManager( - read_config_path=[config_dir], - write_config_dir=os.path.join(config_dir, "jupyter_server_config.d"), - ) - if enabled: - manager.enable(import_name) - else: - manager.disable(import_name) - - -# ---------------------------------------------------------------------- -# Applications -# ---------------------------------------------------------------------- - -flags = {} -flags.update(BaseExtensionApp.flags) -flags.pop("y", None) -flags.pop("generate-config", None) -flags.update( - { - "user": ( - { - "ToggleServerExtensionApp": { - "user": True, - } - }, - "Perform the operation for the current user", - ), - "system": ( - { - "ToggleServerExtensionApp": { - "user": False, - "sys_prefix": False, - } - }, - "Perform the operation system-wide", - ), - "sys-prefix": ( - { - "ToggleServerExtensionApp": { - "sys_prefix": True, - } - }, - "Use sys.prefix as the prefix for installing server extensions", - ), - "py": ( - { - "ToggleServerExtensionApp": { - "python": True, - } - }, - "Install from a Python package", - ), - } -) -flags["python"] = flags["py"] - - -class ToggleServerExtensionApp(BaseExtensionApp): - """A base class for enabling/disabling extensions""" - - name = "Kennen server extension enable/disable" - description = "Enable/disable a server extension using frontend configuration files." - - flags = flags - - _toggle_value = Bool() - _toggle_pre_message = "" - _toggle_post_message = "" - - def toggle_server_extension(self, import_name): - """Change the status of a named server extension. - - Uses the value of `self._toggle_value`. - - Parameters - --------- - - import_name : str - Importable Python module (dotted-notation) exposing the magic-named - `load_jupyter_server_extension` function - """ - # Create an extension manager for this instance. - config_dir, extension_manager = _get_extmanager_for_context( - user=self.user, sys_prefix=self.sys_prefix - ) - try: - self.log.info("{}: {}".format(self._toggle_pre_message.capitalize(), import_name)) - self.log.info("- Writing config: {}".format(config_dir)) - # Validate the server extension. - self.log.info(" - Validating {}...".format(import_name)) - # Interface with the Extension Package and validate. - extpkg = ExtensionPackage(name=import_name) - extpkg.validate() - version = extpkg.version - self.log.info(" {} {} {}".format(import_name, version, GREEN_OK)) - - # Toggle extension config. - config = extension_manager.config_manager - if self._toggle_value is True: - config.enable(import_name) - else: - config.disable(import_name) - - # If successful, let's log. - self.log.info(" - Extension successfully {}.".format(self._toggle_post_message)) - except Exception as err: - self.log.info(" {} Validation failed: {}".format(RED_X, err)) - - def start(self): - """Perform the App's actions as configured""" - if not self.extra_args: - sys.exit("Please specify a server extension/package to enable or disable") - for arg in self.extra_args: - self.toggle_server_extension(arg) - - -class EnableServerExtensionApp(ToggleServerExtensionApp): - """An App that enables (and validates) Server Extensions""" - - name = "jupyter server extension enable" - description = """ - Enable a server extension in configuration. - - Usage - jupyter server extension enable [--system|--sys-prefix] - """ - _toggle_value = True - _toggle_pre_message = "enabling" - _toggle_post_message = "enabled" - - -class DisableServerExtensionApp(ToggleServerExtensionApp): - """An App that disables Server Extensions""" - - name = "jupyter server extension disable" - description = """ - Disable a server extension in configuration. - - Usage - jupyter server extension disable [--system|--sys-prefix] - """ - _toggle_value = False - _toggle_pre_message = "disabling" - _toggle_post_message = "disabled" - - -class ListServerExtensionsApp(BaseExtensionApp): - """An App that lists (and validates) Server Extensions""" - - name = "jupyter server extension list" - version = __version__ - description = "List all server extensions known by the configuration system" - - def list_server_extensions(self): - """List all enabled and disabled server extensions, by config path - - Enabled extensions are validated, potentially generating warnings. - """ - configurations = ( - {"user": True, "sys_prefix": False}, - {"user": False, "sys_prefix": True}, - {"user": False, "sys_prefix": False}, - ) - - for option in configurations: - config_dir, ext_manager = _get_extmanager_for_context(**option) - self.log.info("Config dir: {}".format(config_dir)) - for name, extension in ext_manager.extensions.items(): - enabled = extension.enabled - # Attempt to get extension metadata - self.log.info(" {} {}".format(name, GREEN_ENABLED if enabled else RED_DISABLED)) - try: - self.log.info(" - Validating {}...".format(name)) - if not extension.validate(): - raise ValueError("validation failed") - version = extension.version - self.log.info(" {} {} {}".format(name, version, GREEN_OK)) - except Exception as err: - self.log.warn(" {} {}".format(RED_X, err)) - # Add a blank line between paths. - self.log.info("") - - def start(self): - """Perform the App's actions as configured""" - self.list_server_extensions() - - -_examples = """ -jupyter server extension list # list all configured server extensions -jupyter server extension enable --py # enable all server extensions in a Python package -jupyter server extension disable --py # disable all server extensions in a Python package -""" - - -class ServerExtensionApp(BaseExtensionApp): - """Root level server extension app""" - - name = "jupyter server extension" - version = __version__ - description = "Work with Jupyter server extensions" - examples = _examples - - subcommands = dict( - enable=(EnableServerExtensionApp, "Enable a server extension"), - disable=(DisableServerExtensionApp, "Disable a server extension"), - list=(ListServerExtensionsApp, "List server extensions"), - ) - - def start(self): - """Perform the App's actions as configured""" - super(ServerExtensionApp, self).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. - subcmds = ", ".join(sorted(self.subcommands)) - sys.exit("Please supply at least one subcommand: %s" % subcmds) - - -main = ServerExtensionApp.launch_instance - - -if __name__ == "__main__": - main() diff --git a/server/jupyter_server/extension/utils.py b/server/jupyter_server/extension/utils.py deleted file mode 100644 index afca322..0000000 --- a/server/jupyter_server/extension/utils.py +++ /dev/null @@ -1,103 +0,0 @@ -import importlib -import warnings - - -class ExtensionLoadingError(Exception): - pass - - -class ExtensionMetadataError(Exception): - pass - - -class ExtensionModuleNotFound(Exception): - pass - - -class NotAnExtensionApp(Exception): - pass - - -def get_loader(obj, logger=None): - """Looks for _load_jupyter_server_extension as an attribute - of the object or module. - - Adds backwards compatibility for old function name missing the - underscore prefix. - """ - try: - func = getattr(obj, "_load_jupyter_server_extension") - except AttributeError: - func = getattr(obj, "load_jupyter_server_extension") - warnings.warn( - "A `_load_jupyter_server_extension` function was not " - "found in {name!s}. Instead, a `load_jupyter_server_extension` " - "function was found and will be used for now. This function " - "name will be deprecated in future releases " - "of Jupyter Server.".format(name=obj), - DeprecationWarning, - ) - except Exception: - raise ExtensionLoadingError("_load_jupyter_server_extension function was not found.") - return func - - -def get_metadata(package_name, logger=None): - """Find the extension metadata from an extension package. - - This looks for a `_jupyter_server_extension_points` function - that returns metadata about all extension points within a Jupyter - Server Extension pacakge. - - If it doesn't exist, return a basic metadata packet given - the module name. - """ - module = importlib.import_module(package_name) - - try: - return module, module._jupyter_server_extension_points() - except AttributeError: - pass - - # For backwards compatibility, we temporarily allow - # _jupyter_server_extension_paths. We will remove in - # a later release of Jupyter Server. - try: - extension_points = module._jupyter_server_extension_paths() - if logger: - logger.warning( - "A `_jupyter_server_extension_points` function was not " - "found in {name}. Instead, a `_jupyter_server_extension_paths` " - "function was found and will be used for now. This function " - "name will be deprecated in future releases " - "of Jupyter Server.".format(name=package_name) - ) - return module, extension_points - except AttributeError: - pass - - # Dynamically create metadata if the package doesn't - # provide it. - if logger: - logger.debug( - "A `_jupyter_server_extension_points` function was " - "not found in {name}, so Jupyter Server will look " - "for extension points in the extension pacakge's " - "root.".format(name=package_name) - ) - return module, [{"module": package_name, "name": package_name}] - - -def validate_extension(name): - """Raises an exception is the extension is missing a needed - hook or metadata field. - An extension is valid if: - 1) name is an importable Python package. - 1) the package has a _jupyter_server_extension_paths function - 2) each extension path has a _load_jupyter_server_extension function - - If this works, nothing should happen. - """ - from .manager import ExtensionPackage - - return ExtensionPackage(name=name) diff --git a/server/jupyter_server/files/__init__.py b/server/jupyter_server/files/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/files/handlers.py b/server/jupyter_server/files/handlers.py deleted file mode 100644 index 2b53145..0000000 --- a/server/jupyter_server/files/handlers.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Serve files directly from the ContentsManager.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -import mimetypes -from base64 import decodebytes - -from tornado import web - -from jupyter_server.auth import authorized -from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.utils import ensure_async - -AUTH_RESOURCE = "contents" - - -class FilesHandler(JupyterHandler): - """serve files via ContentsManager - - Normally used when ContentsManager is not a FileContentsManager. - - FileContentsManager subclasses use AuthenticatedFilesHandler by default, - a subclass of StaticFileHandler. - """ - - auth_resource = AUTH_RESOURCE - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the notebook server. - return super(FilesHandler, self).content_security_policy + "; sandbox allow-scripts" - - @web.authenticated - @authorized - def head(self, path): - self.get(path, include_body=False) - self.check_xsrf_cookie() - return self.get(path, include_body=False) - - @web.authenticated - @authorized - async def get(self, path, include_body=True): - # /files/ requests must originate from the same site - self.check_xsrf_cookie() - cm = self.contents_manager - - if await ensure_async(cm.is_hidden(path)) and not cm.allow_hidden: - self.log.info("Refusing to serve hidden file, via 404 Error") - raise web.HTTPError(404) - - path = path.strip("/") - if "/" in path: - _, name = path.rsplit("/", 1) - else: - name = path - - model = await ensure_async(cm.get(path, type="file", content=include_body)) - - if self.get_argument("download", False): - self.set_attachment_header(name) - - # get mimetype from filename - if name.lower().endswith(".ipynb"): - self.set_header("Content-Type", "application/x-ipynb+json") - else: - cur_mime, encoding = mimetypes.guess_type(name) - if cur_mime == "text/plain": - self.set_header("Content-Type", "text/plain; charset=UTF-8") - # RFC 6713 - if encoding == "gzip": - self.set_header("Content-Type", "application/gzip") - elif encoding is not None: - self.set_header("Content-Type", "application/octet-stream") - elif cur_mime is not None: - self.set_header("Content-Type", cur_mime) - else: - if model["format"] == "base64": - self.set_header("Content-Type", "application/octet-stream") - else: - self.set_header("Content-Type", "text/plain; charset=UTF-8") - - if include_body: - if model["format"] == "base64": - b64_bytes = model["content"].encode("ascii") - self.write(decodebytes(b64_bytes)) - elif model["format"] == "json": - self.write(json.dumps(model["content"])) - else: - self.write(model["content"]) - self.flush() - - -default_handlers = [] diff --git a/server/jupyter_server/gateway/__init__.py b/server/jupyter_server/gateway/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/gateway/gateway_client.py b/server/jupyter_server/gateway/gateway_client.py deleted file mode 100644 index 4efbd2e..0000000 --- a/server/jupyter_server/gateway/gateway_client.py +++ /dev/null @@ -1,438 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -import os -from socket import gaierror - -from tornado import web -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPError -from traitlets import Bool -from traitlets import default -from traitlets import Float -from traitlets import Int -from traitlets import TraitError -from traitlets import Unicode -from traitlets import validate -from traitlets.config import SingletonConfigurable - - -class GatewayClient(SingletonConfigurable): - """This class manages the configuration. It's its own singleton class so that we - can share these values across all objects. It also contains some helper methods - to build request arguments out of the various config options. - - """ - - url = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The url of the Kernel or Enterprise Gateway server where - kernel specifications are defined and kernel management takes place. - If defined, this Notebook server acts as a proxy for all kernel - management and kernel specification retrieval. (JUPYTER_GATEWAY_URL env var) - """, - ) - - url_env = "JUPYTER_GATEWAY_URL" - - @default("url") - def _url_default(self): - return os.environ.get(self.url_env) - - @validate("url") - def _url_validate(self, proposal): - value = proposal["value"] - # Ensure value, if present, starts with 'http' - if value is not None and len(value) > 0: - if not str(value).lower().startswith("http"): - raise TraitError("GatewayClient url must start with 'http': '%r'" % value) - return value - - ws_url = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The websocket url of the Kernel or Enterprise Gateway server. If not provided, this value - will correspond to the value of the Gateway url with 'ws' in place of 'http'. (JUPYTER_GATEWAY_WS_URL env var) - """, - ) - - ws_url_env = "JUPYTER_GATEWAY_WS_URL" - - @default("ws_url") - def _ws_url_default(self): - default_value = os.environ.get(self.ws_url_env) - if default_value is None: - if self.gateway_enabled: - default_value = self.url.lower().replace("http", "ws") - return default_value - - @validate("ws_url") - def _ws_url_validate(self, proposal): - value = proposal["value"] - # Ensure value, if present, starts with 'ws' - if value is not None and len(value) > 0: - if not str(value).lower().startswith("ws"): - raise TraitError("GatewayClient ws_url must start with 'ws': '%r'" % value) - return value - - kernels_endpoint_default_value = "/api/kernels" - kernels_endpoint_env = "JUPYTER_GATEWAY_KERNELS_ENDPOINT" - kernels_endpoint = Unicode( - default_value=kernels_endpoint_default_value, - config=True, - help="""The gateway API endpoint for accessing kernel resources (JUPYTER_GATEWAY_KERNELS_ENDPOINT env var)""", - ) - - @default("kernels_endpoint") - def _kernels_endpoint_default(self): - return os.environ.get(self.kernels_endpoint_env, self.kernels_endpoint_default_value) - - kernelspecs_endpoint_default_value = "/api/kernelspecs" - kernelspecs_endpoint_env = "JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT" - kernelspecs_endpoint = Unicode( - default_value=kernelspecs_endpoint_default_value, - config=True, - help="""The gateway API endpoint for accessing kernelspecs (JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT env var)""", - ) - - @default("kernelspecs_endpoint") - def _kernelspecs_endpoint_default(self): - return os.environ.get( - self.kernelspecs_endpoint_env, self.kernelspecs_endpoint_default_value - ) - - kernelspecs_resource_endpoint_default_value = "/kernelspecs" - kernelspecs_resource_endpoint_env = "JUPYTER_GATEWAY_KERNELSPECS_RESOURCE_ENDPOINT" - kernelspecs_resource_endpoint = Unicode( - default_value=kernelspecs_resource_endpoint_default_value, - config=True, - help="""The gateway endpoint for accessing kernelspecs resources - (JUPYTER_GATEWAY_KERNELSPECS_RESOURCE_ENDPOINT env var)""", - ) - - @default("kernelspecs_resource_endpoint") - def _kernelspecs_resource_endpoint_default(self): - return os.environ.get( - self.kernelspecs_resource_endpoint_env, - self.kernelspecs_resource_endpoint_default_value, - ) - - connect_timeout_default_value = 40.0 - connect_timeout_env = "JUPYTER_GATEWAY_CONNECT_TIMEOUT" - connect_timeout = Float( - default_value=connect_timeout_default_value, - config=True, - help="""The time allowed for HTTP connection establishment with the Gateway server. - (JUPYTER_GATEWAY_CONNECT_TIMEOUT env var)""", - ) - - @default("connect_timeout") - def connect_timeout_default(self): - return float( - os.environ.get("JUPYTER_GATEWAY_CONNECT_TIMEOUT", self.connect_timeout_default_value) - ) - - request_timeout_default_value = 40.0 - request_timeout_env = "JUPYTER_GATEWAY_REQUEST_TIMEOUT" - request_timeout = Float( - default_value=request_timeout_default_value, - config=True, - help="""The time allowed for HTTP request completion. (JUPYTER_GATEWAY_REQUEST_TIMEOUT env var)""", - ) - - @default("request_timeout") - def request_timeout_default(self): - return float( - os.environ.get("JUPYTER_GATEWAY_REQUEST_TIMEOUT", self.request_timeout_default_value) - ) - - client_key = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The filename for client SSL key, if any. (JUPYTER_GATEWAY_CLIENT_KEY env var) - """, - ) - client_key_env = "JUPYTER_GATEWAY_CLIENT_KEY" - - @default("client_key") - def _client_key_default(self): - return os.environ.get(self.client_key_env) - - client_cert = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The filename for client SSL certificate, if any. (JUPYTER_GATEWAY_CLIENT_CERT env var) - """, - ) - client_cert_env = "JUPYTER_GATEWAY_CLIENT_CERT" - - @default("client_cert") - def _client_cert_default(self): - return os.environ.get(self.client_cert_env) - - ca_certs = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The filename of CA certificates or None to use defaults. (JUPYTER_GATEWAY_CA_CERTS env var) - """, - ) - ca_certs_env = "JUPYTER_GATEWAY_CA_CERTS" - - @default("ca_certs") - def _ca_certs_default(self): - return os.environ.get(self.ca_certs_env) - - http_user = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The username for HTTP authentication. (JUPYTER_GATEWAY_HTTP_USER env var) - """, - ) - http_user_env = "JUPYTER_GATEWAY_HTTP_USER" - - @default("http_user") - def _http_user_default(self): - return os.environ.get(self.http_user_env) - - http_pwd = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The password for HTTP authentication. (JUPYTER_GATEWAY_HTTP_PWD env var) - """, - ) - http_pwd_env = "JUPYTER_GATEWAY_HTTP_PWD" - - @default("http_pwd") - def _http_pwd_default(self): - return os.environ.get(self.http_pwd_env) - - headers_default_value = "{}" - headers_env = "JUPYTER_GATEWAY_HEADERS" - headers = Unicode( - default_value=headers_default_value, - allow_none=True, - config=True, - help="""Additional HTTP headers to pass on the request. This value will be converted to a dict. - (JUPYTER_GATEWAY_HEADERS env var) - """, - ) - - @default("headers") - def _headers_default(self): - return os.environ.get(self.headers_env, self.headers_default_value) - - auth_token = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The authorization token used in the HTTP headers. The header will be formatted as:: - - { - 'Authorization': '{auth_scheme} {auth_token}' - } - - (JUPYTER_GATEWAY_AUTH_TOKEN env var)""", - ) - auth_token_env = "JUPYTER_GATEWAY_AUTH_TOKEN" - - @default("auth_token") - def _auth_token_default(self): - return os.environ.get(self.auth_token_env, "") - - auth_scheme = Unicode( - default_value=None, - allow_none=True, - config=True, - help="""The auth scheme, added as a prefix to the authorization token used in the HTTP headers. - (JUPYTER_GATEWAY_AUTH_SCHEME env var)""", - ) - auth_scheme_env = "JUPYTER_GATEWAY_AUTH_SCHEME" - - @default("auth_scheme") - def _auth_scheme_default(self): - return os.environ.get(self.auth_scheme_env, "token") - - validate_cert_default_value = True - validate_cert_env = "JUPYTER_GATEWAY_VALIDATE_CERT" - validate_cert = Bool( - default_value=validate_cert_default_value, - config=True, - help="""For HTTPS requests, determines if server's certificate should be validated or not. - (JUPYTER_GATEWAY_VALIDATE_CERT env var)""", - ) - - @default("validate_cert") - def validate_cert_default(self): - return bool( - os.environ.get(self.validate_cert_env, str(self.validate_cert_default_value)) - not in ["no", "false"] - ) - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self._static_args = {} # initialized on first use - - env_whitelist_default_value = "" - env_whitelist_env = "JUPYTER_GATEWAY_ENV_WHITELIST" - env_whitelist = Unicode( - default_value=env_whitelist_default_value, - config=True, - help="""A comma-separated list of environment variable names that will be included, along with - their values, in the kernel startup request. The corresponding `env_whitelist` configuration - value must also be set on the Gateway server - since that configuration value indicates which - environmental values to make available to the kernel. (JUPYTER_GATEWAY_ENV_WHITELIST env var)""", - ) - - @default("env_whitelist") - def _env_whitelist_default(self): - return os.environ.get(self.env_whitelist_env, self.env_whitelist_default_value) - - gateway_retry_interval_default_value = 1.0 - gateway_retry_interval_env = "JUPYTER_GATEWAY_RETRY_INTERVAL" - gateway_retry_interval = Float( - default_value=gateway_retry_interval_default_value, - config=True, - help="""The time allowed for HTTP reconnection with the Gateway server for the first time. - Next will be JUPYTER_GATEWAY_RETRY_INTERVAL multiplied by two in factor of numbers of retries - but less than JUPYTER_GATEWAY_RETRY_INTERVAL_MAX. - (JUPYTER_GATEWAY_RETRY_INTERVAL env var)""", - ) - - @default("gateway_retry_interval") - def gateway_retry_interval_default(self): - return float( - os.environ.get( - "JUPYTER_GATEWAY_RETRY_INTERVAL", - self.gateway_retry_interval_default_value, - ) - ) - - gateway_retry_interval_max_default_value = 30.0 - gateway_retry_interval_max_env = "JUPYTER_GATEWAY_RETRY_INTERVAL_MAX" - gateway_retry_interval_max = Float( - default_value=gateway_retry_interval_max_default_value, - config=True, - help="""The maximum time allowed for HTTP reconnection retry with the Gateway server. - (JUPYTER_GATEWAY_RETRY_INTERVAL_MAX env var)""", - ) - - @default("gateway_retry_interval_max") - def gateway_retry_interval_max_default(self): - return float( - os.environ.get( - "JUPYTER_GATEWAY_RETRY_INTERVAL_MAX", - self.gateway_retry_interval_max_default_value, - ) - ) - - gateway_retry_max_default_value = 5 - gateway_retry_max_env = "JUPYTER_GATEWAY_RETRY_MAX" - gateway_retry_max = Int( - default_value=gateway_retry_max_default_value, - config=True, - help="""The maximum retries allowed for HTTP reconnection with the Gateway server. - (JUPYTER_GATEWAY_RETRY_MAX env var)""", - ) - - @default("gateway_retry_max") - def gateway_retry_max_default(self): - return int( - os.environ.get("JUPYTER_GATEWAY_RETRY_MAX", self.gateway_retry_max_default_value) - ) - - @property - def gateway_enabled(self): - return bool(self.url is not None and len(self.url) > 0) - - # Ensure KERNEL_LAUNCH_TIMEOUT has a default value. - KERNEL_LAUNCH_TIMEOUT = int(os.environ.get("KERNEL_LAUNCH_TIMEOUT", 40)) - - def init_static_args(self): - """Initialize arguments used on every request. Since these are static values, we'll - perform this operation once. - - """ - # Ensure that request timeout and KERNEL_LAUNCH_TIMEOUT are the same, taking the - # greater value of the two. - if self.request_timeout < float(GatewayClient.KERNEL_LAUNCH_TIMEOUT): - self.request_timeout = float(GatewayClient.KERNEL_LAUNCH_TIMEOUT) - elif self.request_timeout > float(GatewayClient.KERNEL_LAUNCH_TIMEOUT): - GatewayClient.KERNEL_LAUNCH_TIMEOUT = int(self.request_timeout) - # Ensure any adjustments are reflected in env. - os.environ["KERNEL_LAUNCH_TIMEOUT"] = str(GatewayClient.KERNEL_LAUNCH_TIMEOUT) - - self._static_args["headers"] = json.loads(self.headers) - if "Authorization" not in self._static_args["headers"].keys(): - self._static_args["headers"].update( - {"Authorization": "{} {}".format(self.auth_scheme, self.auth_token)} - ) - self._static_args["connect_timeout"] = self.connect_timeout - self._static_args["request_timeout"] = self.request_timeout - self._static_args["validate_cert"] = self.validate_cert - if self.client_cert: - self._static_args["client_cert"] = self.client_cert - self._static_args["client_key"] = self.client_key - if self.ca_certs: - self._static_args["ca_certs"] = self.ca_certs - if self.http_user: - self._static_args["auth_username"] = self.http_user - if self.http_pwd: - self._static_args["auth_password"] = self.http_pwd - - def load_connection_args(self, **kwargs): - """Merges the static args relative to the connection, with the given keyword arguments. If statics - have yet to be initialized, we'll do that here. - - """ - if len(self._static_args) == 0: - self.init_static_args() - - kwargs.update(self._static_args) - return kwargs - - -async def gateway_request(endpoint, **kwargs): - """Make an async request to kernel gateway endpoint, returns a response""" - client = AsyncHTTPClient() - kwargs = GatewayClient.instance().load_connection_args(**kwargs) - try: - response = await client.fetch(endpoint, **kwargs) - # Trap a set of common exceptions so that we can inform the user that their Gateway url is incorrect - # or the server is not running. - # NOTE: We do this here since this handler is called during the Notebook's startup and subsequent refreshes - # of the tree view. - except ConnectionRefusedError as e: - raise web.HTTPError( - 503, - "Connection refused from Gateway server url '{}'. " - "Check to be sure the Gateway instance is running.".format( - GatewayClient.instance().url - ), - ) from e - except HTTPError as e: - # This can occur if the host is valid (e.g., foo.com) but there's nothing there. - raise web.HTTPError( - e.code, - "Error attempting to connect to Gateway server url '{}'. " - "Ensure gateway url is valid and the Gateway instance is running.".format( - GatewayClient.instance().url - ), - ) from e - except gaierror as e: - raise web.HTTPError( - 404, - "The Gateway server specified in the gateway_url '{}' doesn't appear to be valid. " - "Ensure gateway url is valid and the Gateway instance is running.".format( - GatewayClient.instance().url - ), - ) from e - - return response diff --git a/server/jupyter_server/gateway/handlers.py b/server/jupyter_server/gateway/handlers.py deleted file mode 100644 index 3e86cbe..0000000 --- a/server/jupyter_server/gateway/handlers.py +++ /dev/null @@ -1,292 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import asyncio -import logging -import mimetypes -import os -import random - -from ipython_genutils.py3compat import cast_unicode -from jupyter_client.session import Session -from tornado import web -from tornado.concurrent import Future -from tornado.escape import json_decode -from tornado.escape import url_escape -from tornado.escape import utf8 -from tornado.httpclient import HTTPRequest -from tornado.ioloop import IOLoop -from tornado.ioloop import PeriodicCallback -from tornado.websocket import websocket_connect -from tornado.websocket import WebSocketHandler -from traitlets.config.configurable import LoggingConfigurable - -from ..base.handlers import APIHandler -from ..base.handlers import JupyterHandler -from ..utils import url_path_join -from .managers import GatewayClient - -# Keepalive ping interval (default: 30 seconds) -GATEWAY_WS_PING_INTERVAL_SECS = int(os.getenv("GATEWAY_WS_PING_INTERVAL_SECS", 30)) - - -class WebSocketChannelsHandler(WebSocketHandler, JupyterHandler): - - session = None - gateway = None - kernel_id = None - ping_callback = None - - def check_origin(self, origin=None): - return JupyterHandler.check_origin(self, origin) - - def set_default_headers(self): - """Undo the set_default_headers in JupyterHandler which doesn't make sense for websockets""" - pass - - def get_compression_options(self): - # use deflate compress websocket - return {} - - def authenticate(self): - """Run before finishing the GET request - - Extend this method to add logic that should fire before - the websocket finishes completing. - """ - # authenticate the request before opening the websocket - if self.get_current_user() is None: - self.log.warning("Couldn't authenticate WebSocket connection") - raise web.HTTPError(403) - - if self.get_argument("session_id", False): - self.session.session = cast_unicode(self.get_argument("session_id")) - else: - self.log.warning("No session ID specified") - - def initialize(self): - self.log.debug("Initializing websocket connection %s", self.request.path) - self.session = Session(config=self.config) - self.gateway = GatewayWebSocketClient(gateway_url=GatewayClient.instance().url) - - async def get(self, kernel_id, *args, **kwargs): - self.authenticate() - self.kernel_id = cast_unicode(kernel_id, "ascii") - await super(WebSocketChannelsHandler, self).get(kernel_id=kernel_id, *args, **kwargs) - - def send_ping(self): - if self.ws_connection is None and self.ping_callback is not None: - self.ping_callback.stop() - return - - self.ping(b"") - - def open(self, kernel_id, *args, **kwargs): - """Handle web socket connection open to notebook server and delegate to gateway web socket handler""" - self.ping_callback = PeriodicCallback(self.send_ping, GATEWAY_WS_PING_INTERVAL_SECS * 1000) - self.ping_callback.start() - - self.gateway.on_open( - kernel_id=kernel_id, - message_callback=self.write_message, - compression_options=self.get_compression_options(), - ) - - def on_message(self, message): - """Forward message to gateway web socket handler.""" - self.gateway.on_message(message) - - def write_message(self, message, binary=False): - """Send message back to notebook client. This is called via callback from self.gateway._read_messages.""" - if self.ws_connection: # prevent WebSocketClosedError - if isinstance(message, bytes): - binary = True - super(WebSocketChannelsHandler, self).write_message(message, binary=binary) - elif self.log.isEnabledFor(logging.DEBUG): - msg_summary = WebSocketChannelsHandler._get_message_summary(json_decode(utf8(message))) - self.log.debug( - "Notebook client closed websocket connection - message dropped: {}".format( - msg_summary - ) - ) - - def on_close(self): - self.log.debug("Closing websocket connection %s", self.request.path) - self.gateway.on_close() - super(WebSocketChannelsHandler, self).on_close() - - @staticmethod - def _get_message_summary(message): - summary = [] - message_type = message["msg_type"] - summary.append("type: {}".format(message_type)) - - if message_type == "status": - summary.append(", state: {}".format(message["content"]["execution_state"])) - elif message_type == "error": - summary.append( - ", {}:{}:{}".format( - message["content"]["ename"], - message["content"]["evalue"], - message["content"]["traceback"], - ) - ) - else: - summary.append(", ...") # don't display potentially sensitive data - - return "".join(summary) - - -class GatewayWebSocketClient(LoggingConfigurable): - """Proxy web socket connection to a kernel/enterprise gateway.""" - - def __init__(self, **kwargs): - super(GatewayWebSocketClient, self).__init__(**kwargs) - self.kernel_id = None - self.ws = None - self.ws_future = Future() - self.disconnected = False - self.retry = 0 - - async def _connect(self, kernel_id, message_callback): - # websocket is initialized before connection - self.ws = None - self.kernel_id = kernel_id - ws_url = url_path_join( - GatewayClient.instance().ws_url, - GatewayClient.instance().kernels_endpoint, - url_escape(kernel_id), - "channels", - ) - self.log.info("Connecting to {}".format(ws_url)) - kwargs = {} - kwargs = GatewayClient.instance().load_connection_args(**kwargs) - - request = HTTPRequest(ws_url, **kwargs) - self.ws_future = websocket_connect(request) - self.ws_future.add_done_callback(self._connection_done) - - loop = IOLoop.current() - loop.add_future(self.ws_future, lambda future: self._read_messages(message_callback)) - - def _connection_done(self, fut): - if ( - not self.disconnected and fut.exception() is None - ): # prevent concurrent.futures._base.CancelledError - self.ws = fut.result() - self.retry = 0 - self.log.debug("Connection is ready: ws: {}".format(self.ws)) - else: - self.log.warning( - "Websocket connection has been closed via client disconnect or due to error. " - "Kernel with ID '{}' may not be terminated on GatewayClient: {}".format( - self.kernel_id, GatewayClient.instance().url - ) - ) - - def _disconnect(self): - self.disconnected = True - if self.ws is not None: - # Close connection - self.ws.close() - elif not self.ws_future.done(): - # Cancel pending connection. Since future.cancel() is a noop on tornado, we'll track cancellation locally - self.ws_future.cancel() - self.log.debug( - "_disconnect: future cancelled, disconnected: {}".format(self.disconnected) - ) - - async def _read_messages(self, callback): - """Read messages from gateway server.""" - while self.ws is not None: - message = None - if not self.disconnected: - try: - message = await self.ws.read_message() - except Exception as e: - self.log.error( - "Exception reading message from websocket: {}".format(e) - ) # , exc_info=True) - if message is None: - if not self.disconnected: - self.log.warning("Lost connection to Gateway: {}".format(self.kernel_id)) - break - callback( - message - ) # pass back to notebook client (see self.on_open and WebSocketChannelsHandler.open) - else: # ws cancelled - stop reading - break - - # NOTE(esevan): if websocket is not disconnected by client, try to reconnect. - if not self.disconnected and self.retry < GatewayClient.instance().gateway_retry_max: - jitter = random.randint(10, 100) * 0.01 - retry_interval = ( - min( - GatewayClient.instance().gateway_retry_interval * (2**self.retry), - GatewayClient.instance().gateway_retry_interval_max, - ) - + jitter - ) - self.retry += 1 - self.log.info( - "Attempting to re-establish the connection to Gateway in %s secs (%s/%s): %s", - retry_interval, - self.retry, - GatewayClient.instance().gateway_retry_max, - self.kernel_id, - ) - await asyncio.sleep(retry_interval) - loop = IOLoop.current() - loop.spawn_callback(self._connect, self.kernel_id, callback) - - def on_open(self, kernel_id, message_callback, **kwargs): - """Web socket connection open against gateway server.""" - loop = IOLoop.current() - loop.spawn_callback(self._connect, kernel_id, message_callback) - - def on_message(self, message): - """Send message to gateway server.""" - if self.ws is None: - loop = IOLoop.current() - loop.add_future(self.ws_future, lambda future: self._write_message(message)) - else: - self._write_message(message) - - def _write_message(self, message): - """Send message to gateway server.""" - try: - if not self.disconnected and self.ws is not None: - self.ws.write_message(message) - except Exception as e: - self.log.error( - "Exception writing message to websocket: {}".format(e) - ) # , exc_info=True) - - def on_close(self): - """Web socket closed event.""" - self._disconnect() - - -class GatewayResourceHandler(APIHandler): - """Retrieves resources for specific kernelspec definitions from kernel/enterprise gateway.""" - - @web.authenticated - async def get(self, kernel_name, path, include_body=True): - ksm = self.kernel_spec_manager - kernel_spec_res = await ksm.get_kernel_spec_resource(kernel_name, path) - if kernel_spec_res is None: - self.log.warning( - "Kernelspec resource '{}' for '{}' not found. Gateway may not support" - " resource serving.".format(path, kernel_name) - ) - else: - self.set_header("Content-Type", mimetypes.guess_type(path)[0]) - self.finish(kernel_spec_res) - - -from ..services.kernels.handlers import _kernel_id_regex -from ..services.kernelspecs.handlers import kernel_name_regex - -default_handlers = [ - (r"/api/kernels/%s/channels" % _kernel_id_regex, WebSocketChannelsHandler), - (r"/kernelspecs/%s/(?P.*)" % kernel_name_regex, GatewayResourceHandler), -] diff --git a/server/jupyter_server/gateway/managers.py b/server/jupyter_server/gateway/managers.py deleted file mode 100644 index 9462229..0000000 --- a/server/jupyter_server/gateway/managers.py +++ /dev/null @@ -1,718 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import datetime -import json -import os -from logging import Logger -from queue import Queue -from threading import Thread -from typing import Dict - -import websocket -from jupyter_client.asynchronous.client import AsyncKernelClient -from jupyter_client.clientabc import KernelClientABC -from jupyter_client.kernelspec import KernelSpecManager -from jupyter_client.manager import AsyncKernelManager -from jupyter_client.managerabc import KernelManagerABC -from tornado import web -from tornado.escape import json_decode -from tornado.escape import json_encode -from tornado.escape import url_escape -from tornado.escape import utf8 -from traitlets import default -from traitlets import DottedObjectName -from traitlets import Instance -from traitlets import Type - -from .._tz import UTC -from ..services.kernels.kernelmanager import AsyncMappingKernelManager -from ..services.sessions.sessionmanager import SessionManager -from ..utils import ensure_async -from ..utils import url_path_join -from .gateway_client import gateway_request -from .gateway_client import GatewayClient - - -class GatewayMappingKernelManager(AsyncMappingKernelManager): - """Kernel manager that supports remote kernels hosted by Jupyter Kernel or Enterprise Gateway.""" - - # We'll maintain our own set of kernel ids - _kernels: Dict[str, "GatewayKernelManager"] = {} - - @default("kernel_manager_class") - def _default_kernel_manager_class(self): - return "jupyter_server.gateway.managers.GatewayKernelManager" - - @default("shared_context") - def _default_shared_context(self): - return False # no need to share zmq contexts - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.kernels_url = url_path_join( - GatewayClient.instance().url, GatewayClient.instance().kernels_endpoint - ) - - def remove_kernel(self, kernel_id): - """Complete override since we want to be more tolerant of missing keys""" - try: - return self._kernels.pop(kernel_id) - except KeyError: - pass - - async def start_kernel(self, kernel_id=None, path=None, **kwargs): - """Start a kernel for a session and return its kernel_id. - - Parameters - ---------- - kernel_id : uuid - The uuid to associate the new kernel with. If this - is not None, this kernel will be persistent whenever it is - requested. - path : API path - The API path (unicode, '/' delimited) for the cwd. - Will be transformed to an OS path relative to root_dir. - """ - self.log.info(f"Request start kernel: kernel_id={kernel_id}, path='{path}'") - - if kernel_id is None: - if path is not None: - kwargs["cwd"] = self.cwd_for_path(path) - - km = self.kernel_manager_factory(parent=self, log=self.log) - await km.start_kernel(**kwargs) - kernel_id = km.kernel_id - self._kernels[kernel_id] = km - - # Initialize culling if not already - if not self._initialized_culler: - self.initialize_culler() - - return kernel_id - - async def kernel_model(self, kernel_id): - """Return a dictionary of kernel information described in the - JSON standard model. - - Parameters - ---------- - kernel_id : uuid - The uuid of the kernel. - """ - model = None - km = self.get_kernel(kernel_id) - if km: - model = km.kernel - return model - - async def list_kernels(self, **kwargs): - """Get a list of running kernels from the Gateway server. - - We'll use this opportunity to refresh the models in each of - the kernels we're managing. - """ - self.log.debug(f"Request list kernels: {self.kernels_url}") - response = await gateway_request(self.kernels_url, method="GET") - kernels = json_decode(response.body) - # Refresh our models to those we know about, and filter - # the return value with only our kernels. - kernel_models = {} - for model in kernels: - kid = model["id"] - if kid in self._kernels: - await self._kernels[kid].refresh_model(model) - kernel_models[kid] = model - # Remove any of our kernels that may have been culled on the gateway server - our_kernels = self._kernels.copy() - culled_ids = [] - for kid, km in our_kernels.items(): - if kid not in kernel_models: - self.log.warn(f"Kernel {kid} no longer active - probably culled on Gateway server.") - self._kernels.pop(kid, None) - culled_ids.append(kid) # TODO: Figure out what do with these. - return list(kernel_models.values()) - - async def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to shutdown. - now : bool - Shutdown the kernel immediately (True) or gracefully (False) - restart : bool - The purpose of this shutdown is to restart the kernel (True) - """ - km = self.get_kernel(kernel_id) - await km.shutdown_kernel(now=now, restart=restart) - self.remove_kernel(kernel_id) - - async def restart_kernel(self, kernel_id, now=False, **kwargs): - """Restart a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to restart. - """ - km = self.get_kernel(kernel_id) - await km.restart_kernel(now=now, **kwargs) - - async def interrupt_kernel(self, kernel_id, **kwargs): - """Interrupt a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to interrupt. - """ - km = self.get_kernel(kernel_id) - await km.interrupt_kernel() - - async def shutdown_all(self, now=False): - """Shutdown all kernels.""" - for kernel_id in self._kernels: - km = self.get_kernel(kernel_id) - await km.shutdown_kernel(now=now) - self.remove_kernel(kernel_id) - - async def cull_kernels(self): - """Override cull_kernels so we can be sure their state is current.""" - await self.list_kernels() - await super().cull_kernels() - - -class GatewayKernelSpecManager(KernelSpecManager): - def __init__(self, **kwargs): - super().__init__(**kwargs) - base_endpoint = url_path_join( - GatewayClient.instance().url, GatewayClient.instance().kernelspecs_endpoint - ) - - self.base_endpoint = GatewayKernelSpecManager._get_endpoint_for_user_filter(base_endpoint) - self.base_resource_endpoint = url_path_join( - GatewayClient.instance().url, - GatewayClient.instance().kernelspecs_resource_endpoint, - ) - - @staticmethod - def _get_endpoint_for_user_filter(default_endpoint): - kernel_user = os.environ.get("KERNEL_USERNAME") - if kernel_user: - return "?user=".join([default_endpoint, kernel_user]) - return default_endpoint - - def _get_kernelspecs_endpoint_url(https://github.com/self,%20kernel_name=None): - """Builds a url for the kernels endpoint - - Parameters - ---------- - kernel_name : kernel name (optional) - """ - if kernel_name: - return url_path_join(self.base_endpoint, url_escape(kernel_name)) - - return self.base_endpoint - - async def get_all_specs(self): - fetched_kspecs = await self.list_kernel_specs() - - # get the default kernel name and compare to that of this server. - # If different log a warning and reset the default. However, the - # caller of this method will still return this server's value until - # the next fetch of kernelspecs - at which time they'll match. - km = self.parent.kernel_manager - remote_default_kernel_name = fetched_kspecs.get("default") - if remote_default_kernel_name != km.default_kernel_name: - self.log.info( - f"Default kernel name on Gateway server ({remote_default_kernel_name}) differs from " - f"Notebook server ({km.default_kernel_name}). Updating to Gateway server's value." - ) - km.default_kernel_name = remote_default_kernel_name - - remote_kspecs = fetched_kspecs.get("kernelspecs") - return remote_kspecs - - async def list_kernel_specs(self): - """Get a list of kernel specs.""" - kernel_spec_url = self._get_kernelspecs_endpoint_url() - self.log.debug(f"Request list kernel specs at: {kernel_spec_url}") - response = await gateway_request(kernel_spec_url, method="GET") - kernel_specs = json_decode(response.body) - return kernel_specs - - async def get_kernel_spec(self, kernel_name, **kwargs): - """Get kernel spec for kernel_name. - - Parameters - ---------- - kernel_name : str - The name of the kernel. - """ - kernel_spec_url = self._get_kernelspecs_endpoint_url(https://github.com/kernel_name=str(kernel_name)) - self.log.debug(f"Request kernel spec at: {kernel_spec_url}") - try: - response = await gateway_request(kernel_spec_url, method="GET") - except web.HTTPError as error: - if error.status_code == 404: - # Convert not found to KeyError since that's what the Notebook handler expects - # message is not used, but might as well make it useful for troubleshooting - raise KeyError( - "kernelspec {kernel_name} not found on Gateway server at: {gateway_url}".format( - kernel_name=kernel_name, - gateway_url=GatewayClient.instance().url, - ) - ) from error - else: - raise - else: - kernel_spec = json_decode(response.body) - - return kernel_spec - - async def get_kernel_spec_resource(self, kernel_name, path): - """Get kernel spec for kernel_name. - - Parameters - ---------- - kernel_name : str - The name of the kernel. - path : str - The name of the desired resource - """ - kernel_spec_resource_url = url_path_join( - self.base_resource_endpoint, str(kernel_name), str(path) - ) - self.log.debug(f"Request kernel spec resource '{path}' at: {kernel_spec_resource_url}") - try: - response = await gateway_request(kernel_spec_resource_url, method="GET") - except web.HTTPError as error: - if error.status_code == 404: - kernel_spec_resource = None - else: - raise - else: - kernel_spec_resource = response.body - return kernel_spec_resource - - -class GatewaySessionManager(SessionManager): - kernel_manager = Instance("jupyter_server.gateway.managers.GatewayMappingKernelManager") - - async def kernel_culled(self, kernel_id): - """Checks if the kernel is still considered alive and returns true if its not found.""" - kernel = None - try: - km = self.kernel_manager.get_kernel(kernel_id) - kernel = await km.refresh_model() - except Exception: # Let exceptions here reflect culled kernel - pass - return kernel is None - - -"""KernelManager class to manage a kernel running on a Gateway Server via the REST API""" - - -class GatewayKernelManager(AsyncKernelManager): - """Manages a single kernel remotely via a Gateway Server.""" - - kernel_id = None - kernel = None - - @default("cache_ports") - def _default_cache_ports(self): - return False # no need to cache ports here - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.kernels_url = url_path_join( - GatewayClient.instance().url, GatewayClient.instance().kernels_endpoint - ) - self.kernel_url = self.kernel = self.kernel_id = None - # simulate busy/activity markers: - self.execution_state = self.last_activity = None - - @property - def has_kernel(self): - """Has a kernel been started that we are managing.""" - return self.kernel is not None - - client_class = DottedObjectName("jupyter_server.gateway.managers.GatewayKernelClient") - client_factory = Type(klass="jupyter_server.gateway.managers.GatewayKernelClient") - - # -------------------------------------------------------------------------- - # create a Client connected to our Kernel - # -------------------------------------------------------------------------- - - def client(self, **kwargs): - """Create a client configured to connect to our kernel""" - kw = {} - kw.update(self.get_connection_info(session=True)) - kw.update( - dict( - connection_file=self.connection_file, - parent=self, - ) - ) - kw["kernel_id"] = self.kernel_id - - # add kwargs last, for manual overrides - kw.update(kwargs) - return self.client_factory(**kw) - - async def refresh_model(self, model=None): - """Refresh the kernel model. - - Parameters - ---------- - model : dict - The model from which to refresh the kernel. If None, the kernel - model is fetched from the Gateway server. - """ - if model is None: - self.log.debug("Request kernel at: %s" % self.kernel_url) - try: - response = await gateway_request(self.kernel_url, method="GET") - except web.HTTPError as error: - if error.status_code == 404: - self.log.warning("Kernel not found at: %s" % self.kernel_url) - model = None - else: - raise - else: - model = json_decode(response.body) - self.log.debug("Kernel retrieved: %s" % model) - - if model: # Update activity markers - self.last_activity = datetime.datetime.strptime( - model["last_activity"], "%Y-%m-%dT%H:%M:%S.%fZ" - ).replace(tzinfo=UTC) - self.execution_state = model["execution_state"] - if isinstance(self.parent, AsyncMappingKernelManager): - # Update connections only if there's a mapping kernel manager parent for - # this kernel manager. The current kernel manager instance may not have - # an parent instance if, say, a server extension is using another application - # (e.g., papermill) that uses a KernelManager instance directly. - self.parent._kernel_connections[self.kernel_id] = int(model["connections"]) - - self.kernel = model - return model - - # -------------------------------------------------------------------------- - # Kernel management - # -------------------------------------------------------------------------- - - async def start_kernel(self, **kwargs): - """Starts a kernel via HTTP in an asynchronous manner. - - Parameters - ---------- - `**kwargs` : optional - keyword arguments that are passed down to build the kernel_cmd - and launching the kernel (e.g. Popen kwargs). - """ - kernel_id = kwargs.get("kernel_id") - - if kernel_id is None: - kernel_name = kwargs.get("kernel_name", "python3") - self.log.debug("Request new kernel at: %s" % self.kernels_url) - - # Let KERNEL_USERNAME take precedent over http_user config option. - if os.environ.get("KERNEL_USERNAME") is None and GatewayClient.instance().http_user: - os.environ["KERNEL_USERNAME"] = GatewayClient.instance().http_user - - kernel_env = { - k: v - for (k, v) in dict(os.environ).items() - if k.startswith("KERNEL_") or k in GatewayClient.instance().env_whitelist.split(",") - } - - # Add any env entries in this request - kernel_env.update(kwargs.get("env", {})) - - # Convey the full path to where this notebook file is located. - if kwargs.get("cwd") is not None and kernel_env.get("KERNEL_WORKING_DIR") is None: - kernel_env["KERNEL_WORKING_DIR"] = kwargs["cwd"] - - json_body = json_encode({"name": kernel_name, "env": kernel_env}) - - response = await gateway_request(self.kernels_url, method="POST", body=json_body) - self.kernel = json_decode(response.body) - self.kernel_id = self.kernel["id"] - self.log.info( - "GatewayKernelManager started kernel: {}, args: {}".format(self.kernel_id, kwargs) - ) - else: - self.kernel_id = kernel_id - self.kernel = await self.refresh_model() - self.log.info("GatewayKernelManager using existing kernel: {}".format(self.kernel_id)) - - self.kernel_url = url_path_join(self.kernels_url, url_escape(str(self.kernel_id))) - - async def shutdown_kernel(self, now=False, restart=False): - """Attempts to stop the kernel process cleanly via HTTP.""" - - if self.has_kernel: - self.log.debug("Request shutdown kernel at: %s", self.kernel_url) - response = await gateway_request(self.kernel_url, method="DELETE") - self.log.debug("Shutdown kernel response: %d %s", response.code, response.reason) - - async def restart_kernel(self, **kw): - """Restarts a kernel via HTTP.""" - if self.has_kernel: - kernel_url = self.kernel_url + "/restart" - self.log.debug("Request restart kernel at: %s", kernel_url) - response = await gateway_request(kernel_url, method="POST", body=json_encode({})) - self.log.debug("Restart kernel response: %d %s", response.code, response.reason) - - async def interrupt_kernel(self): - """Interrupts the kernel via an HTTP request.""" - if self.has_kernel: - kernel_url = self.kernel_url + "/interrupt" - self.log.debug("Request interrupt kernel at: %s", kernel_url) - response = await gateway_request(kernel_url, method="POST", body=json_encode({})) - self.log.debug("Interrupt kernel response: %d %s", response.code, response.reason) - - async def is_alive(self): - """Is the kernel process still running?""" - if self.has_kernel: - # Go ahead and issue a request to get the kernel - self.kernel = await self.refresh_model() - return True - else: # we don't have a kernel - return False - - def cleanup_resources(self, restart=False): - """Clean up resources when the kernel is shut down""" - pass - - -KernelManagerABC.register(GatewayKernelManager) - - -class ChannelQueue(Queue): - - channel_name: str = None - - def __init__(self, channel_name: str, channel_socket: websocket.WebSocket, log: Logger): - super().__init__() - self.channel_name = channel_name - self.channel_socket = channel_socket - self.log = log - - async def get_msg(self, *args, **kwargs) -> dict: - timeout = kwargs.get("timeout", 1) - msg = self.get(timeout=timeout) - self.log.debug( - "Received message on channel: {}, msg_id: {}, msg_type: {}".format( - self.channel_name, msg["msg_id"], msg["msg_type"] if msg else "null" - ) - ) - self.task_done() - return msg - - def send(self, msg: dict) -> None: - message = json.dumps(msg, default=ChannelQueue.serialize_datetime).replace(" None: - pass - - def stop(self) -> None: - if not self.empty(): - # If unprocessed messages are detected, drain the queue collecting non-status - # messages. If any remain that are not 'shutdown_reply' and this is not iopub - # go ahead and issue a warning. - msgs = [] - while self.qsize(): - msg = self.get_nowait() - if msg["msg_type"] != "status": - msgs.append(msg["msg_type"]) - if self.channel_name == "iopub" and "shutdown_reply" in msgs: - return - if len(msgs): - self.log.warning( - "Stopping channel '{}' with {} unprocessed non-status messages: {}.".format( - self.channel_name, len(msgs), msgs - ) - ) - - def is_alive(self) -> bool: - return self.channel_socket is not None - - -class HBChannelQueue(ChannelQueue): - def is_beating(self) -> bool: - # Just use the is_alive status for now - return self.is_alive() - - -class GatewayKernelClient(AsyncKernelClient): - """Communicates with a single kernel indirectly via a websocket to a gateway server. - - There are five channels associated with each kernel: - - * shell: for request/reply calls to the kernel. - * iopub: for the kernel to publish results to frontends. - * hb: for monitoring the kernel's heartbeat. - * stdin: for frontends to reply to raw_input calls in the kernel. - * control: for kernel management calls to the kernel. - - The messages that can be sent on these channels are exposed as methods of the - client (KernelClient.execute, complete, history, etc.). These methods only - send the message, they don't wait for a reply. To get results, use e.g. - :meth:`get_shell_msg` to fetch messages from the shell channel. - """ - - # flag for whether execute requests should be allowed to call raw_input: - allow_stdin = False - _channels_stopped = False - _channel_queues = {} - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.kernel_id = kwargs["kernel_id"] - self.channel_socket = None - self.response_router = None - - # -------------------------------------------------------------------------- - # Channel management methods - # -------------------------------------------------------------------------- - - async def start_channels(self, shell=True, iopub=True, stdin=True, hb=True, control=True): - """Starts the channels for this kernel. - - For this class, we establish a websocket connection to the destination - and setup the channel-based queues on which applicable messages will - be posted. - """ - - ws_url = url_path_join( - GatewayClient.instance().ws_url, - GatewayClient.instance().kernels_endpoint, - url_escape(self.kernel_id), - "channels", - ) - # Gather cert info in case where ssl is desired... - ssl_options = dict() - ssl_options["ca_certs"] = GatewayClient.instance().ca_certs - ssl_options["certfile"] = GatewayClient.instance().client_cert - ssl_options["keyfile"] = GatewayClient.instance().client_key - - self.channel_socket = websocket.create_connection( - ws_url, - timeout=GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT, - enable_multithread=True, - sslopt=ssl_options, - ) - self.response_router = Thread(target=self._route_responses) - self.response_router.start() - - await ensure_async( - super().start_channels(shell=shell, iopub=iopub, stdin=stdin, hb=hb, control=control) - ) - - def stop_channels(self): - """Stops all the running channels for this kernel. - - For this class, we close the websocket connection and destroy the - channel-based queues. - """ - super().stop_channels() - self._channels_stopped = True - self.log.debug("Closing websocket connection") - - self.channel_socket.close() - self.response_router.join() - - if self._channel_queues: - self._channel_queues.clear() - self._channel_queues = None - - # Channels are implemented via a ChannelQueue that is used to send and receive messages - - @property - def shell_channel(self): - """Get the shell channel object for this kernel.""" - if self._shell_channel is None: - self.log.debug("creating shell channel queue") - self._shell_channel = ChannelQueue("shell", self.channel_socket, self.log) - self._channel_queues["shell"] = self._shell_channel - return self._shell_channel - - @property - def iopub_channel(self): - """Get the iopub channel object for this kernel.""" - if self._iopub_channel is None: - self.log.debug("creating iopub channel queue") - self._iopub_channel = ChannelQueue("iopub", self.channel_socket, self.log) - self._channel_queues["iopub"] = self._iopub_channel - return self._iopub_channel - - @property - def stdin_channel(self): - """Get the stdin channel object for this kernel.""" - if self._stdin_channel is None: - self.log.debug("creating stdin channel queue") - self._stdin_channel = ChannelQueue("stdin", self.channel_socket, self.log) - self._channel_queues["stdin"] = self._stdin_channel - return self._stdin_channel - - @property - def hb_channel(self): - """Get the hb channel object for this kernel.""" - if self._hb_channel is None: - self.log.debug("creating hb channel queue") - self._hb_channel = HBChannelQueue("hb", self.channel_socket, self.log) - self._channel_queues["hb"] = self._hb_channel - return self._hb_channel - - @property - def control_channel(self): - """Get the control channel object for this kernel.""" - if self._control_channel is None: - self.log.debug("creating control channel queue") - self._control_channel = ChannelQueue("control", self.channel_socket, self.log) - self._channel_queues["control"] = self._control_channel - return self._control_channel - - def _route_responses(self): - """ - Reads responses from the websocket and routes each to the appropriate channel queue based - on the message's channel. It does this for the duration of the class's lifetime until the - channels are stopped, at which time the socket is closed (unblocking the router) and - the thread terminates. If shutdown happens to occur while processing a response (unlikely), - termination takes place via the loop control boolean. - """ - try: - while not self._channels_stopped: - raw_message = self.channel_socket.recv() - if not raw_message: - break - response_message = json_decode(utf8(raw_message)) - channel = response_message["channel"] - self._channel_queues[channel].put_nowait(response_message) - - except websocket.WebSocketConnectionClosedException: - pass # websocket closure most likely due to shutdown - - except BaseException as be: - if not self._channels_stopped: - self.log.warning("Unexpected exception encountered ({})".format(be)) - - self.log.debug("Response router thread exiting...") - - -KernelClientABC.register(GatewayKernelClient) diff --git a/server/jupyter_server/i18n/README.md b/server/jupyter_server/i18n/README.md deleted file mode 100644 index a36d026..0000000 --- a/server/jupyter_server/i18n/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# Implementation Notes for Internationalization of Jupyter Notebook - -The implementation of i18n features for jupyter notebook is still a work-in-progress: - -- User interface strings are (mostly) handled -- Console messages are not handled (their usefulness in a translated environment is questionable) -- Tooling has to be refined - -Howeverâ€Ļ - -## How the language is selected ? - -1. `jupyter notebook` command reads the `LANG` environment variable at startup, - (`xx_XX` or just `xx` form, where `xx` is the language code you're wanting to - run in). - -Hint: if running Windows, you can set it in PowerShell with `${Env:LANG} = "xx_XX"`. -if running Ubuntu 14, you should set environment variable `LANGUAGE="xx_XX"`. - -2. The preferred language for web pages in your browser settings (`xx`) is - also used. At the moment, it has to be first in the list. - -## Contributing and managing translations - -### Requirements - -- _pybabel_ (could be installed `pip install babel`) -- _po2json_ (could be installed with `npm install -g po2json`) - -**All i18n-related commands are done from the related directory :** - - cd notebook/i18n/ - -### Message extraction - -The translatable material for notebook is split into 3 `.pot` files, as follows: - -- _notebook/i18n/notebook.pot_ - Console and startup messages, basically anything that is - produced by Python code. -- _notebook/i18n/nbui.pot_ - User interface strings, as extracted from the Jinja2 templates - in _notebook/templates/\*.html_ -- _noteook/i18n/nbjs.pot_ - JavaScript strings and dialogs, which contain much of the visible - user interface for Jupyter notebook. - -To extract the messages from the source code whenever new material is added, use the -`pybabel` command: - -```shell -pybabel extract -F babel_notebook.cfg -o notebook.pot --no-wrap --project Jupyter . -pybabel extract -F babel_nbui.cfg -o nbui.pot --no-wrap --project Jupyter . -pybabel extract -F babel_nbjs.cfg -o nbjs.pot --no-wrap --project Jupyter . -``` - -After this is complete you have 3 `.pot` files that you can give to a translator for your favorite language. - -### Messages compilation - -After the source material has been translated, you should have 3 `.po` files with the same base names -as the `.pot` files above. Put them in `notebook/i18n/${LANG}/LC_MESSAGES`, where `${LANG}` is the language -code for your desired language ( i.e. German = "de", Japanese = "ja", etc. ). - -_notebook.po_ and _nbui.po_ need to be converted from `.po` to `.mo` format for -use at runtime. - -```shell -pybabel compile -D notebook -f -l ${LANG} -i ${LANG}/LC_MESSAGES/notebook.po -o ${LANG}/LC_MESSAGES/notebook.mo -pybabel compile -D nbui -f -l ${LANG} -i ${LANG}/LC_MESSAGES/nbui.po -o ${LANG}/LC_MESSAGES/nbui.mo -``` - -_nbjs.po_ needs to be converted to JSON for use within the JavaScript code, with _po2json_, as follows: - - po2json -p -F -f jed1.x -d nbjs ${LANG}/LC_MESSAGES/nbjs.po ${LANG}/LC_MESSAGES/nbjs.json - -When new languages get added, their language codes should be added to _notebook/i18n/nbjs.json_ -under the `supported_languages` element. - -### Tips for Jupyter developers - -The biggest "mistake" I found while doing i18n enablement was the habit of constructing UI messages -from English "piece parts". For example, code like: - -```javascript -var msg = 'Enter a new ' + type + 'name:'; -``` - -where `type` is either "file", "directory", or "notebook".... - -is problematic when doing translations, because the surrounding text may need to vary -depending on the inserted word. In this case, you need to switch it and use complete phrases, -as follows: - -```javascript -var rename_msg = function (type) { - switch (type) { - case 'file': - return _('Enter a new file name:'); - case 'directory': - return _('Enter a new directory name:'); - case 'notebook': - return _('Enter a new notebook name:'); - default: - return _('Enter a new name:'); - } -}; -``` - -Also you need to remember that adding an "s" or "es" to an English word to -create the plural form doesn't translate well. Some languages have as many as 5 or 6 different -plural forms for differing numbers, so using an API such as ngettext() is necessary in order -to handle these cases properly. - -### Known issues and future evolutions - -1. Right now there are two different places where the desired language is set. At startup time, the Jupyter console's messages pay attention to the setting of the `${LANG}` environment variable - as set in the shell at startup time. Unfortunately, this is also the time where the Jinja2 - environment is set up, which means that the template stuff will always come from this setting. - We really want to be paying attention to the browser's settings for the stuff that happens in the - browser, so we need to be able to retrieve this information after the browser is started and somehow - communicate this back to Jinja2. So far, I haven't yet figured out how to do this, which means that if the \${LANG} at startup doesn't match the browser's settings, you could potentially get a mix - of languages in the UI ( never a good thing ). - -2. We will need to decide if console messages should be translatable, and enable them if desired. -3. The keyboard shortcut editor was implemented after the i18n work was completed, so that portion - does not have translation support at this time. -4. Babel's documentation has instructions on how to integrate messages extraction - into your _setup.py_ so that eventually we can just do: - - ./setup.py extract_messages - -I hope to get this working at some point in the near future. 5. The conversions from `.po` to `.mo` probably can and should be done using `setup.py install`. - -Any questions or comments please let me know @JCEmmons on github (emmo@us.ibm.com) diff --git a/server/jupyter_server/i18n/__init__.py b/server/jupyter_server/i18n/__init__.py deleted file mode 100644 index 2ffa7ad..0000000 --- a/server/jupyter_server/i18n/__init__.py +++ /dev/null @@ -1,101 +0,0 @@ -"""Server functions for loading translations -""" -import errno -import io -import json -import re -from collections import defaultdict -from os.path import dirname -from os.path import join as pjoin - -I18N_DIR = dirname(__file__) -# Cache structure: -# {'nbjs': { # Domain -# 'zh-CN': { # Language code -# : -# ... -# } -# }} -TRANSLATIONS_CACHE = {"nbjs": {}} - - -_accept_lang_re = re.compile( - r""" -(?P[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?) -(\s*;\s*q\s*=\s* - (?P[01](.\d+)?) -)?""", - re.VERBOSE, -) - - -def parse_accept_lang_header(accept_lang): - """Parses the 'Accept-Language' HTTP header. - - Returns a list of language codes in *ascending* order of preference - (with the most preferred language last). - """ - by_q = defaultdict(list) - for part in accept_lang.split(","): - m = _accept_lang_re.match(part.strip()) - if not m: - continue - lang, qvalue = m.group("lang", "qvalue") - # Browser header format is zh-CN, gettext uses zh_CN - lang = lang.replace("-", "_") - if qvalue is None: - qvalue = 1.0 - else: - qvalue = float(qvalue) - if qvalue == 0: - continue # 0 means not accepted - by_q[qvalue].append(lang) - - res = [] - for qvalue, langs in sorted(by_q.items()): - res.extend(sorted(langs)) - return res - - -def load(language, domain="nbjs"): - """Load translations from an nbjs.json file""" - try: - f = io.open(pjoin(I18N_DIR, language, "LC_MESSAGES", "nbjs.json"), encoding="utf-8") - except IOError as e: - if e.errno != errno.ENOENT: - raise - return {} - - with f: - data = json.load(f) - return data["locale_data"][domain] - - -def cached_load(language, domain="nbjs"): - """Load translations for one language, using in-memory cache if available""" - domain_cache = TRANSLATIONS_CACHE[domain] - try: - return domain_cache[language] - except KeyError: - data = load(language, domain) - domain_cache[language] = data - return data - - -def combine_translations(accept_language, domain="nbjs"): - """Combine translations for multiple accepted languages. - - Returns data re-packaged in jed1.x format. - """ - lang_codes = parse_accept_lang_header(accept_language) - combined = {} - for language in lang_codes: - if language == "en": - # en is default, all translations are in frontend. - combined.clear() - else: - combined.update(cached_load(language, domain)) - - combined[""] = {"domain": "nbjs"} - - return {"domain": domain, "locale_data": {domain: combined}} diff --git a/server/jupyter_server/i18n/babel_nbui.cfg b/server/jupyter_server/i18n/babel_nbui.cfg deleted file mode 100644 index 271554a..0000000 --- a/server/jupyter_server/i18n/babel_nbui.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[jinja2: notebook/templates/**.html] - encoding = utf-8 -[extractors] - jinja2 = jinja2.ext:babel_extract diff --git a/server/jupyter_server/i18n/babel_notebook.cfg b/server/jupyter_server/i18n/babel_notebook.cfg deleted file mode 100644 index d4e3cf9..0000000 --- a/server/jupyter_server/i18n/babel_notebook.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: notebook/*.py] -[python: notebook/services/contents/*.py] diff --git a/server/jupyter_server/i18n/nbjs.json b/server/jupyter_server/i18n/nbjs.json deleted file mode 100644 index a263a46..0000000 --- a/server/jupyter_server/i18n/nbjs.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "domain": "nbjs", - "supported_languages": ["zh-CN"], - "locale_data": { - "nbjs": { - "": { - "domain": "nbjs" - } - } - } -} diff --git a/server/jupyter_server/i18n/nbui.pot b/server/jupyter_server/i18n/nbui.pot deleted file mode 100644 index 7ca038e..0000000 --- a/server/jupyter_server/i18n/nbui.pot +++ /dev/null @@ -1,731 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Kennen VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-07 12:48-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "" - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "" - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "" - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "" - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "" - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "" - -#: notebook/templates/notebook.html:205 -msgid "All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells" -msgstr "" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "" - -#: notebook/templates/notebook.html:209 -msgid "Contents will be sent to the kernel for execution, and output will display in the footer of cell" -msgstr "" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "" - -#: notebook/templates/notebook.html:319 -msgid "About Kennen Notebook" -msgstr "" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "" - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "" - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "" - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "" - -#: notebook/templates/notebook.html:278 -#: notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "" - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "" - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "" - -#: notebook/templates/tree.html:98 -msgid " Folders" -msgstr "" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "" - -#: notebook/templates/tree.html:99 -msgid " All Notebooks" -msgstr "" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "" - -#: notebook/templates/tree.html:100 -msgid " Running" -msgstr "" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "" - -#: notebook/templates/tree.html:101 -msgid " Files" -msgstr "" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "" - -#: notebook/templates/tree.html:130 -msgid "Currently running Kennen processes" -msgstr "" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "" - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "" - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "" - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "" - -#: notebook/templates/tree.html:179 -msgid "See 'IPython parallel' for installation details." -msgstr "" diff --git a/server/jupyter_server/i18n/notebook.pot b/server/jupyter_server/i18n/notebook.pot deleted file mode 100644 index 272e514..0000000 --- a/server/jupyter_server/i18n/notebook.pot +++ /dev/null @@ -1,442 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Kennen VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: jupyter_server/serverapp.py:53 -msgid "The Kennen Server requires tornado >= 4.0" -msgstr "" - -#: jupyter_server/serverapp.py:57 -msgid "The Kennen Server requires tornado >= 4.0, but you have < 1.1.0" -msgstr "" - -#: jupyter_server/serverapp.py:59 -#, python-format -msgid "The Kennen Server requires tornado >= 4.0, but you have %s" -msgstr "" - -#: jupyter_server/serverapp.py:389 -msgid "List currently running Kennen servers." -msgstr "" - -#: jupyter_server/serverapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "" - -#: jupyter_server/serverapp.py:397 -msgid "If True, each line of output will be a JSON object with the details from the server info file." -msgstr "" - -#: jupyter_server/serverapp.py:402 -msgid "Currently running servers:" -msgstr "" - -#: jupyter_server/serverapp.py:419 -msgid "Don't open the kennen_server in a browser after startup." -msgstr "" - -#: jupyter_server/serverapp.py:423 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" - -#: jupyter_server/serverapp.py:439 -msgid "Allow the server to be run from root user." -msgstr "" - -#: jupyter_server/serverapp.py:470 -msgid "" -"The Kennen Server.\n" -" \n" -" This launches a Tornado-based Kennen Server." -msgstr "" - -#: jupyter_server/serverapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "" - -#: jupyter_server/serverapp.py:544 -msgid "Whether to allow the user to run the Jupyter server as root." -msgstr "" - -#: jupyter_server/serverapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "" - -#: jupyter_server/serverapp.py:552 -msgid "The IP address the Jupyter server will listen on." -msgstr "" - -#: jupyter_server/serverapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" - -#: jupyter_server/serverapp.py:579 -msgid "The port the Kennen server will listen on." -msgstr "" - -#: jupyter_server/serverapp.py:583 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "" - -#: jupyter_server/serverapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "" - -#: jupyter_server/serverapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "" - -#: jupyter_server/serverapp.py:595 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "" - -#: jupyter_server/serverapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "" - -#: jupyter_server/serverapp.py:628 -#, python-format -msgid "Writing Kennen server cookie secret to %s" -msgstr "" - -#: jupyter_server/serverapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "" - -#: jupyter_server/serverapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" - -#: jupyter_server/serverapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" - -#: jupyter_server/serverapp.py:726 -msgid "" -"Specify Where to open the server on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" - -#: jupyter_server/serverapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" - -#: jupyter_server/serverapp.py:746 -msgid "Supply overrides for the tornado.web.Application that the Jupyter server uses." -msgstr "" - -#: jupyter_server/serverapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" - -#: jupyter_server/serverapp.py:761 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" - -#: jupyter_server/serverapp.py:764 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "" - -#: jupyter_server/serverapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" - -#: jupyter_server/serverapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "" - -#: jupyter_server/serverapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "" - -#: jupyter_server/serverapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "" - -#: jupyter_server/serverapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "" - -#: jupyter_server/serverapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from kennen_server.templates." -msgstr "" - -#: jupyter_server/serverapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "" - -#: jupyter_server/serverapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "" - -#: jupyter_server/serverapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "" - -#: jupyter_server/serverapp.py:920 -msgid "The kernel manager class to use." -msgstr "" - -#: jupyter_server/serverapp.py:926 -msgid "The session manager class to use." -msgstr "" - -#: jupyter_server/serverapp.py:932 -msgid "The config manager class to use" -msgstr "" - -#: jupyter_server/serverapp.py:953 -msgid "The login handler class to use." -msgstr "" - -#: jupyter_server/serverapp.py:960 -msgid "The logout handler class to use." -msgstr "" - -#: jupyter_server/serverapp.py:964 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "" - -#: jupyter_server/serverapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" - -#: jupyter_server/serverapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "" - -#: jupyter_server/serverapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "" - -#: jupyter_server/serverapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "" - -#: jupyter_server/serverapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "" - -#: jupyter_server/serverapp.py:1036 -msgid "server_extensions is deprecated, use jpserver_extensions" -msgstr "" - -#: jupyter_server/serverapp.py:1040 -msgid "Dict of Python modules to load as notebook server extensions. Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "" - -#: jupyter_server/serverapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "" - -#: jupyter_server/serverapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: jupyter_server/serverapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: jupyter_server/serverapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" - -#: jupyter_server/serverapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "" - -#: jupyter_server/serverapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "" - -#: jupyter_server/serverapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "" - -#: jupyter_server/serverapp.py:1143 -msgid "\t$ python -m jupyter_server.auth password" -msgstr "" - -#: jupyter_server/serverapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "" - -#: jupyter_server/serverapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "" - -#: jupyter_server/serverapp.py:1193 -msgid "ERROR: the Jupyter server could not be started because no available port could be found." -msgstr "" - -#: jupyter_server/serverapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "" - -#: jupyter_server/serverapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "" - -#: jupyter_server/serverapp.py:1259 -msgid "interrupted" -msgstr "" - -#: jupyter_server/serverapp.py:1261 -msgid "y" -msgstr "" - -#: jupyter_server/serverapp.py:1262 -msgid "n" -msgstr "" - -#: jupyter_server/serverapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "" - -#: jupyter_server/serverapp.py:1269 -msgid "Shutdown confirmed" -msgstr "" - -#: jupyter_server/serverapp.py:1273 -msgid "No answer for 5s:" -msgstr "" - -#: jupyter_server/serverapp.py:1274 -msgid "resuming operation..." -msgstr "" - -#: jupyter_server/serverapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "" - -#: jupyter_server/serverapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "" - -#: jupyter_server/serverapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "" - -#: jupyter_server/serverapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "" -msgstr[1] "" - -#: jupyter_server/serverapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"\r" -"%s" -msgstr "" - -#: jupyter_server/serverapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "" - -#: jupyter_server/serverapp.py:1432 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "" - -#: jupyter_server/serverapp.py:1434 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "" - -#: jupyter_server/serverapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "" - -#: jupyter_server/serverapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "" - -#: jupyter_server/serverapp.py:1484 -msgid "Interrupted..." -msgstr "" - -#: jupyter_server/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "" - -#: jupyter_server/services/contents/manager.py:68 -msgid "Untitled" -msgstr "" diff --git a/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/nbui.po b/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/nbui.po deleted file mode 100644 index a8ccac2..0000000 --- a/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,731 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Kennen VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-08-25 02:53-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.0\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "č¯ˇæą‚įš„äģŖį ä¸å­˜åœ¨!" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "åŊ“å‰æ¨Ąåŧ" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "文äģļ" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "新åģē" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "äŋå­˜" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "重å‘Ŋ名" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "下čŊŊ" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "įŧ–čž‘" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "æŸĨ扞" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "æŸĨ扞 & æ›ŋæĸ" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "键å€ŧ寚" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "éģ˜čޤ" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "äģŖį įŧ–čž‘å™¨" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "æŸĨįœ‹" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "昞į¤ē/隐藏 标éĸ˜å’Œlogo" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "切æĸHeader" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "切æĸčĄŒåˇ" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "蝭荀" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "错蝝:" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "å¯†į æˆ–č€…token:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "坆᠁:" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "į™ģåŊ•" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "čŋ˜æ˛Ąæœ‰į™ģåŊ•, č¯ˇå…ˆį™ģåŊ•." - -#: notebook/templates/logout.html:31 -#, python-format -msgid "Proceed to the dashboard" -msgstr "čŋ›å…Ĩ 指į¤ēæŋ" - -#: notebook/templates/logout.html:33 -#, python-format -msgid "Proceed to the login page" -msgstr "čŋ›å…Ĩ į™ģåŊ•éĄĩéĸ" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "čœå•" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "æœåŠĄ" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "čŋ™ä¸ĒäģŖį æ˜¯åĒč¯ģįš„" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "新åģēäģŖį " - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "äģĨäģĒčĄ¨į›˜č§†č§’æ‰“åŧ€æ–°įš„įĒ—åŖ" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "打åŧ€..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "打åŧ€äģŖį å†…åŽšįš„å‰¯æœŦåšļ启动一ä¸Ēæ–°įš„æœåŠĄ" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "复åˆļ..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "重å‘Ŋ名..." - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "äŋå­˜" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "æĸ复" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "打印éĸ„č§ˆ" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "下čŊŊ" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "äģŖį (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "脚æœŦ" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "部įŊ˛åœ¨" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "äŋĄäģģäģŖį įš„čž“å‡ē" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "äŋĄäģģäģŖį " - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "å…ŗé—­äģŖį æœåŠĄåšļå…ŗé—­įĒ—åŖ" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "å…ŗé—­" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "å‰Ē切äģŖį å—" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "复åˆļäģŖį å—" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "ម贴到䏊éĸ" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "į˛˜č´´åˆ°ä¸‹éĸ" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "ម贴äģŖį å— & æ›ŋæĸ" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "删除äģŖį å—" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "撤销删除" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "åˆ†å‰˛äģŖį å—" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "合åšļ上éĸįš„äģŖį å—" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "合åšļ下éĸįš„äģŖį å—" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "上į§ģäģŖį å—" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "下į§ģäģŖį å—" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "įŧ–čž‘į•Œéĸ元数捎" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "æŸĨ扞åšļæ›ŋæĸ" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "å‰Ē切附äģļ" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "复åˆļ附äģļ" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "į˛˜č´´é™„äģļ" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "插å…Ĩå›žį‰‡" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "昞į¤ē/隐藏 操äŊœå›žæ ‡" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "昞į¤ē/éšč—čĄŒåˇ" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "单元æ ŧåˇĨå…ˇæ " - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "插å…Ĩ" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "在åŊ“前æ´ģ动单元上插å…Ĩ一ä¸ĒįŠēįš„äģŖį å•å…ƒæ ŧ" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "插å…Ĩ单元æ ŧ上éĸ" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "在åŊ“前æ´ģ动单元下éĸ插å…Ĩ一ä¸ĒįŠēįš„äģŖį å•å…ƒæ ŧ" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "插å…Ĩ单元æ ŧ下éĸ" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "单元æ ŧ" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "čŋčĄŒčŋ™ä¸Ē单元æ ŧīŧŒåšļ将光标į§ģ到下一ä¸Ē" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "čŋčĄŒæ‰€æœ‰å•å…ƒæ ŧ" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "čŋčĄŒæ­¤å•å…ƒīŧŒé€‰æ‹ŠäģĨ下选项" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "čŋčĄŒå•å…ƒæ ŧåšļč‡Ē动选拊下一ä¸Ē" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "čŋčĄŒå•å…ƒæ ŧåšļ选拊äģĨ下" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "čŋčĄŒå•å…ƒæ ŧåšļ在下éĸ插å…Ĩ" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "čŋčĄŒæ‰€æœ‰įš„单元æ ŧ" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "čŋčĄŒæ‰€æœ‰" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "čŋčĄŒä¸Šéĸįš„æ‰€æœ‰å•å…ƒ(äŊ†ä¸åŒ…æ‹Ŧ)čŋ™ä¸Ē单元æ ŧ" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "čŋčĄŒä¸Šéĸįš„äģŖį å—" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "čŋčĄŒåŊ“前及äģĨ下äģŖį å—" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "čŋčĄŒä¸‹éĸįš„äģŖį å—" - -#: notebook/templates/notebook.html:205 -msgid "All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells" -msgstr "äģŖį é‡Œįš„æ‰€æœ‰å•å…ƒæ ŧéƒŊ有一ä¸Ēįąģ型. éģ˜čŽ¤æƒ…å†ĩ下, 新单元čĸĢ创åģēä¸ē'Code'单元æ ŧ" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "单元æ ŧįąģ型" - -#: notebook/templates/notebook.html:209 -msgid "Contents will be sent to the kernel for execution, and output will display in the footer of cell" -msgstr "内厚将čĸĢ发送到内核äģĨæ‰§čĄŒ, 输å‡ē将昞į¤ē在单元æ ŧįš„éĄĩ脚." - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "内厚将äģĨHTMLåŊĸåŧå‘ˆįް, åšļäŊœä¸ēč§Ŗé‡Šæ€§æ–‡æœŦ" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "æ ‡į­ž" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "内厚将通čŋ‡æœĒįģäŋŽæ”šįš„nbconvert" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "åŽŸį”Ÿ NBConvert" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "åŊ“å‰čž“å‡ē" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "隐藏/昞į¤ēåŊ“前单元æ ŧ输å‡ē" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "切æĸ" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "æģšåЍåŊ“前单元æ ŧįš„čž“å‡ē" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "切æĸæģšåЍ" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "清除åŊ“前单元æ ŧįš„čž“å‡ē" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "清įŠē" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "æ‰€æœ‰čž“å‡ē" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "隐藏/昞į¤ē 所有äģŖį å—įš„čž“å‡ē" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "æģšåŠ¨æ‰€æœ‰å•å…ƒæ ŧįš„čž“å‡ē" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "清įŠē所有äģŖį å—įš„čž“å‡ē" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "按下CTRL-C ä¸­æ–­æœåŠĄ" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "中断" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "é‡å¯æœåŠĄ" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "重启" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "é‡å¯æœåŠĄåšļ清įŠēæ‰€æœ‰čž“å‡ē" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "重启 & 清įŠē输å‡ē" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "é‡å¯æœåŠĄåšļ且重新čŋčĄŒäģŖį " - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "重启 & čŋčĄŒæ‰€æœ‰" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "重新čŋžæŽĨæœåŠĄ" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "重čŋž" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "æ”šå˜æœåŠĄ" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "帎劊" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "åŋĢ速æĩč§ˆä¸€ä¸‹notebookį”¨æˆˇį•Œéĸ" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "į”¨æˆˇį•Œéĸ䚋旅" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "打åŧ€æ‰€æœ‰åŋĢæˇé”Žæį¤ēäŋĄæ¯" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "åŋĢæˇé”Ž" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "打åŧ€å¯šč¯æĄ†įŧ–čž‘åŋĢæˇé”Ž" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "įŧ–čž‘åŋĢæˇé”Ž" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "帎劊" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "在新įĒ—åŖæ‰“åŧ€" - -#: notebook/templates/notebook.html:319 -msgid "About Kennen Notebook" -msgstr "å…ŗäēŽæœŦፋåē" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "å…ŗäēŽ" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Jupyter Notebook需čĻįš„JavaScript." - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "č¯ˇå…čŽ¸åŽƒįģ§įģ­." - -#: notebook/templates/page.html:122 -msgid "dashboard" -msgstr "指į¤ēæŋ" - -#: notebook/templates/page.html:135 -msgid "Logout" -msgstr "æŗ¨é”€" - -#: notebook/templates/page.html:137 -msgid "Login" -msgstr "į™ģåŊ•" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "文äģļ" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "čŋčĄŒ" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "é›†įž¤" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "选拊操äŊœå¯ščąĄ." - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "复åˆļé€‰æ‹Šįš„å¯ščąĄ" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "复åˆļ" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "重å‘Ŋ名" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "į§ģ动" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "į§ģ动" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "下čŊŊ" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "停æ­ĸčŋčĄŒé€‰æ‹Šįš„notebook(s)" - -#: notebook/templates/notebook.html:278 -#: notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "å…ŗé—­" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "æŸĨįœ‹" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "įŧ–čž‘" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "删除" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "į‚šå‡ģæĩč§ˆæ–‡äģļ上äŧ " - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "上äŧ " - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "文æœŦ文äģļ" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "文äģļ多" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "įģˆį̝" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "įģˆįĢ¯ä¸å¯į”¨" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "åˆˇæ–°įŦ”čŽ°åˆ—čĄ¨" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "全选 / 全部选" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "选拊..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "选拊所有文äģļ多" - -#: notebook/templates/tree.html:98 -msgid " Folders" -msgstr "文äģļ多" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "选拊所有įŦ”čް" - -#: notebook/templates/tree.html:99 -msgid " All Notebooks" -msgstr "所有įŦ”čް" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "选拊čŋčĄŒä¸­įš„įŦ”čް" - -#: notebook/templates/tree.html:100 -msgid " Running" -msgstr "čŋčĄŒ" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "选拊所有文äģļ" - -#: notebook/templates/tree.html:101 -msgid " Files" -msgstr "文äģļ" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "最后äŋŽæ”š" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "名字" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "åŊ“前čŋčĄŒJupyter" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "åˆˇæ–°čŋčĄŒåˆ—襨" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "æ˛Ąæœ‰įģˆį̝čŋčĄŒ" - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "įģˆįĢ¯ä¸å¯į”¨" - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "įŦ”čް" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "æ˛Ąæœ‰įŦ”čŽ°æ­Ŗåœ¨čŋčĄŒ" - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "é›†įž¤æ ‡į­žįŽ°åœ¨į”ąIPythonåšļčĄŒæäž›." - -#: notebook/templates/tree.html:179 -msgid "See 'IPython parallel' for installation details." -msgstr "åŽ‰čŖ…įģ†čŠ‚æŸĨįœ‹ 'IPython parallel'." diff --git a/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/notebook.po b/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/notebook.po deleted file mode 100644 index f09d563..0000000 --- a/server/jupyter_server/i18n/zh_CN/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,446 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Kennen VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-08-25 02:53-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.0\n" - -#: notebook/serverapp.py:49 -msgid "The Kennen Notebook requires tornado >= 4.0" -msgstr "č¯ĨፋåēčĻæą‚ tornado į‰ˆæœŦ >= 4.0" - -#: notebook/serverapp.py:53 -msgid "The Kennen Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "č¯ĨፋåēčĻæą‚ tornado į‰ˆæœŦ >= 4.0, å¯æ˜¯įŽ°åŽžå´æ˜¯ < 1.1.0" - -#: notebook/serverapp.py:55 -#, python-format -msgid "The Kennen Notebook requires tornado >= 4.0, but you have %s" -msgstr "č¯ĨፋåēčĻæą‚ tornado į‰ˆæœŦ >= 4.0, å¯æ˜¯įŽ°åŽžå´æ˜¯ %s" - -#: notebook/serverapp.py:206 -#, python-format -msgid "Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "在äŊŋᔍnotebookįš„JavaScript和LESSæ—ļīŧŒå¯äģĨæ›ŋæĸäŊŋᔍ `%s` " - -#: notebook/serverapp.py:385 -msgid "List currently running notebook servers." -msgstr "列å‡ēåŊ“前čŋčĄŒįš„NotebookæœåŠĄ." - -#: notebook/serverapp.py:389 -msgid "Produce machine-readable JSON list output." -msgstr "į”Ÿæˆæœē器可č¯ģįš„JSON输å‡ē." - -#: notebook/serverapp.py:391 -msgid "Produce machine-readable JSON object on each line of output." -msgstr "åŊ“前čŋčĄŒįš„æœåŠĄ" - -#: notebook/serverapp.py:395 -msgid "If True, the output will be a JSON list of objects, one per active notebook server, each with the details from the relevant server info file." -msgstr "åĻ‚æžœæ˜¯æ­ŖįĄŽįš„īŧŒčž“å‡ē将是一ä¸Ēå¯ščąĄįš„JSONåˆ—čĄ¨īŧŒä¸€ä¸Ēæ´ģåŠ¨įš„įŦ”čްæœŦæœåŠĄå™¨īŧŒæ¯ä¸€ä¸ĒéƒŊæœ‰į›¸å…ŗįš„æœåŠĄå™¨äŋĄæ¯æ–‡äģļįš„č¯Ļįģ†äŋĄæ¯ã€‚" - -#: notebook/serverapp.py:399 -msgid "If True, each line of output will be a JSON object with the details from the server info file. For a JSON list output, see the NbserverListApp.jsonlist configuration value" -msgstr "åĻ‚æžœæ˜¯æ­ŖįĄŽįš„īŧŒæ¯ä¸€čĄŒčž“å‡ē将是一ä¸ĒJSONå¯ščąĄīŧŒå…ļ中有æĨč‡ĒæœåŠĄå™¨äŋĄæ¯æ–‡äģļįš„č¯Ļįģ†äŋĄæ¯ã€‚寚äēŽä¸€ä¸ĒJSONåˆ—čĄ¨čž“å‡ēīŧŒč¯ˇå‚阅NbserverListApp。jsonlist配įŊŽå€ŧ" - -#: notebook/serverapp.py:425 -msgid "Don't open the notebook in a browser after startup." -msgstr "åœ¨å¯åŠ¨æœåŠĄäģĨ后不在æĩč§ˆå™¨ä¸­æ‰“åŧ€ä¸€ä¸ĒįĒ—åŖ." - -#: notebook/serverapp.py:429 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" - -#: notebook/serverapp.py:445 -msgid "Allow the notebook to be run from root user." -msgstr "å…čŽ¸notebook在rootį”¨æˆˇä¸‹čŋčĄŒ." - -#: notebook/serverapp.py:476 -msgid "" -"The Kennen HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "The Jupyter HTML Notebook.\n \n čŋ™å°†å¯åЍ䏀ä¸ĒåŸēäēŽtornadoįš„HTMLįŦ”čްæœŦæœåŠĄå™¨īŧŒåŽƒæäž›ä¸€ä¸Ēhtml5/javascriptįŦ”čްæœŦåŽĸæˆˇįĢ¯ã€‚" - -#: notebook/serverapp.py:546 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "莞įŊŽAccess-Control-Allow-Credentials:trueæŠĨ头" - -#: notebook/serverapp.py:550 -msgid "Whether to allow the user to run the notebook as root." -msgstr "是åĻå…čŽ¸notebook在rootį”¨æˆˇä¸‹čŋčĄŒ." - -#: notebook/serverapp.py:554 -msgid "The default URL to redirect to from `/`" -msgstr "äģŽ `/` é‡åŽšå‘åˆ°įš„éģ˜čޤURL " - -#: notebook/serverapp.py:558 -msgid "The IP address the notebook server will listen on." -msgstr "notebookæœåŠĄäŧšį›‘åŦįš„IP地址." - -#: notebook/serverapp.py:571 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "不čƒŊįģ‘åޚ到localhost, äŊŋᔍ127.0.0.1äŊœä¸ēéģ˜čŽ¤įš„IP \n %s" - -#: notebook/serverapp.py:585 -msgid "The port the notebook server will listen on." -msgstr "notebookæœåŠĄäŧšį›‘åŦįš„IPįĢ¯åŖ." - -#: notebook/serverapp.py:589 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "åĻ‚æžœæŒ‡åŽšįš„įĢ¯åŖä¸å¯į”¨īŧŒåˆ™čĻå°č¯•å…ļäģ–įĢ¯åŖįš„æ•°é‡." - -#: notebook/serverapp.py:593 -msgid "The full path to an SSL/TLS certificate file." -msgstr "SSL/TLS čŽ¤č¯æ–‡äģ￉€åœ¨å…¨čˇ¯åž„." - -#: notebook/serverapp.py:597 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "SSL/TLS ᧁé’Ĩ文äģ￉€åœ¨å…¨čˇ¯åž„." - -#: notebook/serverapp.py:601 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "ᔍäēŽssl/tlsåŽĸæˆˇį̝čēĢäģŊéĒŒč¯įš„č¯äšĻéĸå‘蝁äšĻįš„åŽŒæ•´čˇ¯åž„." - -#: notebook/serverapp.py:605 -msgid "The file where the cookie secret is stored." -msgstr "存攞cookie密é’Ĩįš„æ–‡äģļčĸĢäŋå­˜äē†." - -#: notebook/serverapp.py:634 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "把notebook æœåŠĄcookie坆᠁写å…Ĩ %s" - -#: notebook/serverapp.py:641 -#, python-format -msgid "Could not set permissions on %s" -msgstr "不čƒŊ在 %s 莞įŊŽæƒé™" - -#: notebook/serverapp.py:646 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" - -#: notebook/serverapp.py:656 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" - -#: notebook/serverapp.py:732 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" - -#: notebook/serverapp.py:752 -msgid "Supply overrides for the tornado.web.Application that the Jupyter notebook uses." -msgstr "" - -#: notebook/serverapp.py:756 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" - -#: notebook/serverapp.py:767 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" - -#: notebook/serverapp.py:770 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "" - -#: notebook/serverapp.py:774 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" - -#: notebook/serverapp.py:778 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "" - -#: notebook/serverapp.py:782 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "" - -#: notebook/serverapp.py:838 -msgid "Path to search for custom.js, css" -msgstr "" - -#: notebook/serverapp.py:850 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" - -#: notebook/serverapp.py:861 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "" - -#: notebook/serverapp.py:906 -#, python-format -msgid "Using MathJax: %s" -msgstr "" - -#: notebook/serverapp.py:909 -msgid "The MathJax.js configuration file that is to be used." -msgstr "" - -#: notebook/serverapp.py:914 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "" - -#: notebook/serverapp.py:920 -msgid "The notebook manager class to use." -msgstr "" - -#: notebook/serverapp.py:926 -msgid "The kernel manager class to use." -msgstr "" - -#: notebook/serverapp.py:932 -msgid "The session manager class to use." -msgstr "" - -#: notebook/serverapp.py:938 -msgid "The config manager class to use" -msgstr "" - -#: notebook/serverapp.py:959 -msgid "The login handler class to use." -msgstr "" - -#: notebook/serverapp.py:966 -msgid "The logout handler class to use." -msgstr "" - -#: notebook/serverapp.py:970 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "" - -#: notebook/serverapp.py:982 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" - -#: notebook/serverapp.py:994 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "" - -#: notebook/serverapp.py:996 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "" - -#: notebook/serverapp.py:1001 -msgid "The directory to use for notebooks and kernels." -msgstr "ᔍäēŽįŦ”čްæœŦå’Œå†…æ ¸įš„į›ŽåŊ•。" - -#: notebook/serverapp.py:1024 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "æ˛Ąæœ‰æ‰žåˆ°čˇ¯åž„: '%r' " - -#: notebook/serverapp.py:1046 -msgid "Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "将Pythonæ¨Ąå—äŊœä¸ēįŦ”čްæœŦæœåŠĄå™¨æ‰Šåą•åŠ čŊŊ。可äģĨäŊŋį”¨æĄį›Žå€ŧæĨå¯į”¨å’ŒįĻį”¨æ‰Šåą•įš„åŠ čŊŊ。čŋ™ä盿‰Šåą•å°†äģĨ字母éĄēåēåŠ čŊŊ。" - -#: notebook/serverapp.py:1055 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "重新čŋčĄŒįš„åŧ‚常äŧšé‡åˆ°åŠ čŊŊæœåŠĄå™¨æ‰Šåą•å—?" - -#: notebook/serverapp.py:1058 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/serverapp.py:1062 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/serverapp.py:1066 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "(sec)æ—ļ间įĒ—åŖčĸĢᔍæĨ \n æŖ€æŸĨæļˆæ¯å’Œæ•°æŽé€Ÿįއ限åˆļ." - -#: notebook/serverapp.py:1077 -#, python-format -msgid "No such file or directory: %s" -msgstr "扞不到文äģ￈–æ–‡äģļ多: %s" - -#: notebook/serverapp.py:1147 -msgid "Notebook servers are configured to only be run with a password." -msgstr "æœåŠĄčŽžįŊŽä¸ēåĒčƒŊäŊŋᔍ坆᠁čŋčĄŒ." - -#: notebook/serverapp.py:1148 -msgid "Hint: run the following command to set a password" -msgstr "提į¤ē: čŋčĄŒä¸‹éĸå‘Ŋäģ¤čŽžįŊŽå¯†į " - -#: notebook/serverapp.py:1149 -msgid "\t$ python -m notebook.auth password" -msgstr "" - -#: notebook/serverapp.py:1187 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "įĢ¯åŖ %i 厞įģčĸĢį̙ᔍ, č¯ˇå°č¯•å…ļäģ–įĢ¯åŖ." - -#: notebook/serverapp.py:1190 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "ᛑåŦįĢ¯åŖ %i å¤ąč´Ĩ" - -#: notebook/serverapp.py:1199 -msgid "ERROR: the notebook server could not be started because no available port could be found." -msgstr "错蝝: æœåŠĄå¯åŠ¨å¤ąč´Ĩ因ä¸ēæ˛Ąæœ‰æ‰žåˆ°å¯į”¨įš„įĢ¯åŖ. " - -#: notebook/serverapp.py:1205 -msgid "[all ip addresses on your system]" -msgstr "[įŗģį쟿‰€æœ‰IP地址]" - -#: notebook/serverapp.py:1229 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "įģˆįĢ¯ä¸å¯į”¨(错蝝: %s)" - -#: notebook/serverapp.py:1265 -msgid "interrupted" -msgstr "中断" - -#: notebook/serverapp.py:1267 -msgid "y" -msgstr "" - -#: notebook/serverapp.py:1268 -msgid "n" -msgstr "" - -#: notebook/serverapp.py:1269 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "å…ŗé—­æœåŠĄ (%s/[%s])" - -#: notebook/serverapp.py:1275 -msgid "Shutdown confirmed" -msgstr "å…ŗé—­įĄŽåŽš" - -#: notebook/serverapp.py:1279 -msgid "No answer for 5s:" -msgstr "5s æœĒ响åē”" - -#: notebook/serverapp.py:1280 -msgid "resuming operation..." -msgstr "重启操äŊœ..." - -#: notebook/serverapp.py:1288 -#, python-format -msgid "received signal %s, stopping" -msgstr "æŽĨ受äŋĄåˇ %s, æ­Ŗåœ¨åœæ­ĸ" - -#: notebook/serverapp.py:1344 -#, python-format -msgid "Error loading server extension %s" -msgstr "加čŊŊ插äģļ %s å¤ąč´Ĩ" - -#: notebook/serverapp.py:1375 -#, python-format -msgid "Shutting down %d kernel" -msgid_plural "Shutting down %d kernels" -msgstr[0] "å…ŗé—­ %d æœåŠĄ" -msgstr[1] "å…ŗé—­ %d æœåŠĄ" - -#: notebook/serverapp.py:1383 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "%d æ´ģčˇƒįš„æœåŠĄ" -msgstr[1] "%d æ´ģčˇƒįš„æœåŠĄ" - -#: notebook/serverapp.py:1387 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"%s" -msgstr "æœŦፋåēčŋčĄŒåœ¨: %s" - -#: notebook/serverapp.py:1434 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "不åģē莎äģĨrootčēĢäģŊčŋčĄŒ.äŊŋᔍ--allow-rootįģ•čŋ‡čŋ‡." - -#: notebook/serverapp.py:1440 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "äŊŋᔍcontrol-c停æ­ĸæ­¤æœåŠĄå™¨åšļå…ŗé—­æ‰€æœ‰å†…æ ¸(两æŦĄčˇŗčŋ‡įĄŽčޤ)." - -#: notebook/serverapp.py:1442 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "æŦĸčŋŽæĨåˆ°éĄšį›ŽJupyter! æŽĸį´ĸå¯į”¨įš„å„į§åˇĨå…ˇåŠå…ļᛏåē”įš„æ–‡æĄŖ. åĻ‚æžœäŊ æœ‰å…´čļŖå¯ščŋ™ä¸Ēåšŗå°,蝎čŽŋ问http://jupyter.org/community.html community resources部分." - -#: notebook/serverapp.py:1453 -#, python-format -msgid "No web browser found: %s." -msgstr "æ˛Ąæœ‰æ‰žåˆ°webæĩč§ˆå™¨: %s." - -#: notebook/serverapp.py:1458 -#, python-format -msgid "%s does not exist" -msgstr "%s 不存在" - -#: notebook/serverapp.py:1492 -msgid "Interrupted..." -msgstr "厞įģä¸­æ–­..." - -#: notebook/services/contents/filemanager.py:525 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "启动notebooks 在æœŦåœ°čˇ¯åž„: %s" - -#: notebook/services/contents/manager.py:69 -msgid "Untitled" -msgstr "æœĒå‘Ŋ名" diff --git a/server/jupyter_server/kernelspecs/__init__.py b/server/jupyter_server/kernelspecs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/kernelspecs/handlers.py b/server/jupyter_server/kernelspecs/handlers.py deleted file mode 100644 index 437670d..0000000 --- a/server/jupyter_server/kernelspecs/handlers.py +++ /dev/null @@ -1,37 +0,0 @@ -from tornado import web - -from ..base.handlers import JupyterHandler -from ..services.kernelspecs.handlers import kernel_name_regex -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "kernelspecs" - - -class KernelSpecResourceHandler(web.StaticFileHandler, JupyterHandler): - SUPPORTED_METHODS = ("GET", "HEAD") - auth_resource = AUTH_RESOURCE - - def initialize(self): - web.StaticFileHandler.initialize(self, path="") - - @web.authenticated - @authorized - def get(self, kernel_name, path, include_body=True): - ksm = self.kernel_spec_manager - try: - self.root = ksm.get_kernel_spec(kernel_name).resource_dir - except KeyError as e: - raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name) from e - self.log.debug("Serving kernel resource from: %s", self.root) - return web.StaticFileHandler.get(self, path, include_body=include_body) - - @web.authenticated - @authorized - def head(self, kernel_name, path): - return self.get(kernel_name, path, include_body=False) - - -default_handlers = [ - (r"/kernelspecs/%s/(?P.*)" % kernel_name_regex, KernelSpecResourceHandler), -] diff --git a/server/jupyter_server/log.py b/server/jupyter_server/log.py deleted file mode 100644 index 3fd63c7..0000000 --- a/server/jupyter_server/log.py +++ /dev/null @@ -1,56 +0,0 @@ -# ----------------------------------------------------------------------------- -# Copyright (c) Jupyter Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -# ----------------------------------------------------------------------------- -import json - -from tornado.log import access_log - -from .prometheus.log_functions import prometheus_log_method - - -def log_request(handler): - """log a bit more information about each request than tornado's default - - - move static file get success to debug-level (reduces noise) - - get proxied IP instead of proxy IP - - log referer for redirect and failed requests - - log user-agent for failed requests - """ - status = handler.get_status() - request = handler.request - try: - logger = handler.log - except AttributeError: - logger = access_log - - if status < 300 or status == 304: - # Successes (or 304 FOUND) are debug-level - log_method = logger.debug - elif status < 400: - log_method = logger.info - elif status < 500: - log_method = logger.warning - else: - log_method = logger.error - - request_time = 1000.0 * handler.request.request_time() - ns = dict( - status=status, - method=request.method, - ip=request.remote_ip, - uri=request.uri, - request_time=request_time, - ) - msg = "{status} {method} {uri} ({ip}) {request_time:.2f}ms" - if status >= 400: - # log bad referers - ns["referer"] = request.headers.get("Referer", "None") - msg = msg + " referer={referer}" - if status >= 500 and status != 502: - # log all headers if it caused an error - log_method(json.dumps(dict(request.headers), indent=2)) - log_method(msg.format(**ns)) - prometheus_log_method(handler) diff --git a/server/jupyter_server/nbconvert/__init__.py b/server/jupyter_server/nbconvert/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/nbconvert/handlers.py b/server/jupyter_server/nbconvert/handlers.py deleted file mode 100644 index 84efaab..0000000 --- a/server/jupyter_server/nbconvert/handlers.py +++ /dev/null @@ -1,197 +0,0 @@ -"""Tornado handlers for nbconvert.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import io -import os -import zipfile - -from anyio.to_thread import run_sync -from ipython_genutils import text -from ipython_genutils.py3compat import cast_bytes -from nbformat import from_dict -from tornado import web -from tornado.log import app_log - -from ..base.handlers import FilesRedirectHandler -from ..base.handlers import JupyterHandler -from ..base.handlers import path_regex -from jupyter_server.auth import authorized -from jupyter_server.utils import ensure_async - - -AUTH_RESOURCE = "nbconvert" - - -def find_resource_files(output_files_dir): - files = [] - for dirpath, dirnames, filenames in os.walk(output_files_dir): - files.extend([os.path.join(dirpath, f) for f in filenames]) - return files - - -def respond_zip(handler, name, output, resources): - """Zip up the output and resource files and respond with the zip file. - - Returns True if it has served a zip file, False if there are no resource - files, in which case we serve the plain output file. - """ - # Check if we have resource files we need to zip - output_files = resources.get("outputs", None) - if not output_files: - return False - - # Headers - zip_filename = os.path.splitext(name)[0] + ".zip" - handler.set_attachment_header(zip_filename) - handler.set_header("Content-Type", "application/zip") - handler.set_header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") - - # Prepare the zip file - buffer = io.BytesIO() - zipf = zipfile.ZipFile(buffer, mode="w", compression=zipfile.ZIP_DEFLATED) - output_filename = os.path.splitext(name)[0] + resources["output_extension"] - zipf.writestr(output_filename, cast_bytes(output, "utf-8")) - for filename, data in output_files.items(): - zipf.writestr(os.path.basename(filename), data) - zipf.close() - - handler.finish(buffer.getvalue()) - return True - - -def get_exporter(format, **kwargs): - """get an exporter, raising appropriate errors""" - # if this fails, will raise 500 - try: - from nbconvert.exporters.base import get_exporter - except ImportError as e: - raise web.HTTPError(500, "Could not import nbconvert: %s" % e) from e - - try: - Exporter = get_exporter(format) - except KeyError as e: - # should this be 400? - raise web.HTTPError(404, "No exporter for format: %s" % format) from e - - try: - return Exporter(**kwargs) - except Exception as e: - app_log.exception("Could not construct Exporter: %s", Exporter) - raise web.HTTPError(500, "Could not construct Exporter: %s" % e) from e - - -class NbconvertFileHandler(JupyterHandler): - - auth_resource = AUTH_RESOURCE - SUPPORTED_METHODS = ("GET",) - - @web.authenticated - @authorized - async def get(self, format, path): - self.check_xsrf_cookie() - exporter = get_exporter(format, config=self.config, log=self.log) - - path = path.strip("/") - # If the notebook relates to a real file (default contents manager), - # give its path to nbconvert. - if hasattr(self.contents_manager, "_get_os_path"): - os_path = self.contents_manager._get_os_path(path) - ext_resources_dir, basename = os.path.split(os_path) - else: - ext_resources_dir = None - - model = await ensure_async(self.contents_manager.get(path=path)) - name = model["name"] - if model["type"] != "notebook": - # not a notebook, redirect to files - return FilesRedirectHandler.redirect_to_files(self, path) - - nb = model["content"] - - self.set_header("Last-Modified", model["last_modified"]) - - # create resources dictionary - mod_date = model["last_modified"].strftime(text.date_format) - nb_title = os.path.splitext(name)[0] - - resource_dict = { - "metadata": {"name": nb_title, "modified_date": mod_date}, - "config_dir": self.application.settings["config_dir"], - } - - if ext_resources_dir: - resource_dict["metadata"]["path"] = ext_resources_dir - - # Exporting can take a while, delegate to a thread so we don't block the event loop - try: - output, resources = await run_sync( - lambda: exporter.from_notebook_node(nb, resources=resource_dict) - ) - except Exception as e: - self.log.exception("nbconvert failed: %s", e) - raise web.HTTPError(500, "nbconvert failed: %s" % e) from e - - if respond_zip(self, name, output, resources): - return - - # Force download if requested - if self.get_argument("download", "false").lower() == "true": - filename = os.path.splitext(name)[0] + resources["output_extension"] - self.set_attachment_header(filename) - - # MIME type - if exporter.output_mimetype: - self.set_header("Content-Type", "%s; charset=utf-8" % exporter.output_mimetype) - - self.set_header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") - self.finish(output) - - -class NbconvertPostHandler(JupyterHandler): - - SUPPORTED_METHODS = ("POST",) - auth_resource = AUTH_RESOURCE - - @web.authenticated - @authorized - async def post(self, format): - exporter = get_exporter(format, config=self.config) - - model = self.get_json_body() - name = model.get("name", "notebook.ipynb") - nbnode = from_dict(model["content"]) - - try: - output, resources = await run_sync( - lambda: exporter.from_notebook_node( - nbnode, - resources={ - "metadata": {"name": name[: name.rfind(".")]}, - "config_dir": self.application.settings["config_dir"], - }, - ) - ) - except Exception as e: - raise web.HTTPError(500, "nbconvert failed: %s" % e) from e - - if respond_zip(self, name, output, resources): - return - - # MIME type - if exporter.output_mimetype: - self.set_header("Content-Type", "%s; charset=utf-8" % exporter.output_mimetype) - - self.finish(output) - - -# ----------------------------------------------------------------------------- -# URL to handler mappings -# ----------------------------------------------------------------------------- - -_format_regex = r"(?P\w+)" - - -default_handlers = [ - (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler), - (r"/nbconvert/%s%s" % (_format_regex, path_regex), NbconvertFileHandler), -] diff --git a/server/jupyter_server/prometheus/__init__.py b/server/jupyter_server/prometheus/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/prometheus/log_functions.py b/server/jupyter_server/prometheus/log_functions.py deleted file mode 100644 index 1f36ade..0000000 --- a/server/jupyter_server/prometheus/log_functions.py +++ /dev/null @@ -1,24 +0,0 @@ -from .metrics import HTTP_REQUEST_DURATION_SECONDS - - -def prometheus_log_method(handler): - """ - Tornado log handler for recording RED metrics. - - We record the following metrics: - Rate - the number of requests, per second, your services are serving. - Errors - the number of failed requests per second. - Duration - The amount of time each request takes expressed as a time interval. - - We use a fully qualified name of the handler as a label, - rather than every url path to reduce cardinality. - - This function should be either the value of or called from a function - that is the 'log_function' tornado setting. This makes it get called - at the end of every request, allowing us to record the metrics we need. - """ - HTTP_REQUEST_DURATION_SECONDS.labels( - method=handler.request.method, - handler="{}.{}".format(handler.__class__.__module__, type(handler).__name__), - status_code=handler.get_status(), - ).observe(handler.request.request_time()) diff --git a/server/jupyter_server/prometheus/metrics.py b/server/jupyter_server/prometheus/metrics.py deleted file mode 100644 index 7b6746e..0000000 --- a/server/jupyter_server/prometheus/metrics.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Prometheus metrics exported by Jupyter Server - -Read https://prometheus.io/docs/practices/naming/ for naming -conventions for metrics & labels. -""" - -try: - # Jupyter Notebook also defines these metrics. Re-defining them results in a ValueError. - # Try to de-duplicate by using the ones in Notebook if available. - # See https://github.com/jupyter/jupyter_server/issues/209 - from notebook.prometheus.metrics import ( - HTTP_REQUEST_DURATION_SECONDS, - TERMINAL_CURRENTLY_RUNNING_TOTAL, - KERNEL_CURRENTLY_RUNNING_TOTAL, - ) - -except ImportError: - - from prometheus_client import Histogram, Gauge - - HTTP_REQUEST_DURATION_SECONDS = Histogram( - "http_request_duration_seconds", - "duration in seconds for all HTTP requests", - ["method", "handler", "status_code"], - ) - - TERMINAL_CURRENTLY_RUNNING_TOTAL = Gauge( - "terminal_currently_running_total", - "counter for how many terminals are running", - ) - - KERNEL_CURRENTLY_RUNNING_TOTAL = Gauge( - "kernel_currently_running_total", - "counter for how many kernels are running labeled by type", - ["type"], - ) diff --git a/server/jupyter_server/pytest_plugin.py b/server/jupyter_server/pytest_plugin.py deleted file mode 100644 index 45f3f73..0000000 --- a/server/jupyter_server/pytest_plugin.py +++ /dev/null @@ -1,511 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import io -import json -import logging -import os -import shutil -import sys -import urllib.parse -from binascii import hexlify - -import jupyter_core.paths -import nbformat -import pytest -import tornado -from tornado.escape import url_escape -from traitlets.config import Config - -from jupyter_server.extension import serverextension -from jupyter_server.serverapp import ServerApp -from jupyter_server.services.contents.filemanager import FileContentsManager -from jupyter_server.services.contents.largefilemanager import LargeFileManager -from jupyter_server.utils import url_path_join - - -# List of dependencies needed for this plugin. -pytest_plugins = [ - "pytest_tornasync", - # Once the chunk below moves to Jupyter Core, we'll uncomment - # This plugin and use the fixtures directly from Jupyter Core. - # "jupyter_core.pytest_plugin" -] - - -import asyncio - -if os.name == "nt" and sys.version_info >= (3, 7): - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - - -# ============ Move to Jupyter Core ============= - - -def mkdir(tmp_path, *parts): - path = tmp_path.joinpath(*parts) - if not path.exists(): - path.mkdir(parents=True) - return path - - -@pytest.fixture -def jp_home_dir(tmp_path): - """Provides a temporary HOME directory value.""" - return mkdir(tmp_path, "home") - - -@pytest.fixture -def jp_data_dir(tmp_path): - """Provides a temporary Jupyter data dir directory value.""" - return mkdir(tmp_path, "data") - - -@pytest.fixture -def jp_config_dir(tmp_path): - """Provides a temporary Jupyter config dir directory value.""" - return mkdir(tmp_path, "config") - - -@pytest.fixture -def jp_runtime_dir(tmp_path): - """Provides a temporary Jupyter runtime dir directory value.""" - return mkdir(tmp_path, "runtime") - - -@pytest.fixture -def jp_system_jupyter_path(tmp_path): - """Provides a temporary Jupyter system path value.""" - return mkdir(tmp_path, "share", "jupyter") - - -@pytest.fixture -def jp_env_jupyter_path(tmp_path): - """Provides a temporary Jupyter env system path value.""" - return mkdir(tmp_path, "env", "share", "jupyter") - - -@pytest.fixture -def jp_system_config_path(tmp_path): - """Provides a temporary Jupyter config path value.""" - return mkdir(tmp_path, "etc", "jupyter") - - -@pytest.fixture -def jp_env_config_path(tmp_path): - """Provides a temporary Jupyter env config path value.""" - return mkdir(tmp_path, "env", "etc", "jupyter") - - -@pytest.fixture -def jp_environ( - monkeypatch, - tmp_path, - jp_home_dir, - jp_data_dir, - jp_config_dir, - jp_runtime_dir, - jp_system_jupyter_path, - jp_system_config_path, - jp_env_jupyter_path, - jp_env_config_path, -): - """Configures a temporary environment based on Jupyter-specific environment variables.""" - monkeypatch.setenv("HOME", str(jp_home_dir)) - monkeypatch.setenv("PYTHONPATH", os.pathsep.join(sys.path)) - # monkeypatch.setenv("JUPYTER_NO_CONFIG", "1") - monkeypatch.setenv("JUPYTER_CONFIG_DIR", str(jp_config_dir)) - monkeypatch.setenv("JUPYTER_DATA_DIR", str(jp_data_dir)) - monkeypatch.setenv("JUPYTER_RUNTIME_DIR", str(jp_runtime_dir)) - monkeypatch.setattr(jupyter_core.paths, "SYSTEM_JUPYTER_PATH", [str(jp_system_jupyter_path)]) - monkeypatch.setattr(jupyter_core.paths, "ENV_JUPYTER_PATH", [str(jp_env_jupyter_path)]) - monkeypatch.setattr(jupyter_core.paths, "SYSTEM_CONFIG_PATH", [str(jp_system_config_path)]) - monkeypatch.setattr(jupyter_core.paths, "ENV_CONFIG_PATH", [str(jp_env_config_path)]) - - -# ================= End: Move to Jupyter core ================ - - -@pytest.fixture -def jp_server_config(): - """Allows tests to setup their specific configuration values.""" - return {} - - -@pytest.fixture -def jp_root_dir(tmp_path): - """Provides a temporary Jupyter root directory value.""" - return mkdir(tmp_path, "root_dir") - - -@pytest.fixture -def jp_template_dir(tmp_path): - """Provides a temporary Jupyter templates directory value.""" - return mkdir(tmp_path, "templates") - - -@pytest.fixture -def jp_argv(): - """Allows tests to setup specific argv values.""" - return [] - - -@pytest.fixture -def jp_extension_environ(jp_env_config_path, monkeypatch): - """Monkeypatch a Jupyter Extension's config path into each test's environment variable""" - monkeypatch.setattr(serverextension, "ENV_CONFIG_PATH", [str(jp_env_config_path)]) - - -@pytest.fixture -def jp_http_port(http_server_port): - """Returns the port value from the http_server_port fixture.""" - return http_server_port[-1] - - -@pytest.fixture -def jp_nbconvert_templates(jp_data_dir): - """Setups up a temporary directory consisting of the nbconvert templates.""" - - # Get path to nbconvert template directory *before* - # monkeypatching the paths env variable via the jp_environ fixture. - possible_paths = jupyter_core.paths.jupyter_path("nbconvert", "templates") - nbconvert_path = None - for path in possible_paths: - if os.path.exists(path): - nbconvert_path = path - break - - nbconvert_target = jp_data_dir / "nbconvert" / "templates" - - # copy nbconvert templates to new tmp data_dir. - if nbconvert_path: - shutil.copytree(nbconvert_path, str(nbconvert_target)) - - -@pytest.fixture -def jp_logging_stream(): - """StringIO stream intended to be used by the core - Jupyter ServerApp logger's default StreamHandler. This - helps avoid collision with stdout which is hijacked - by Pytest. - """ - logging_stream = io.StringIO() - yield logging_stream - output = logging_stream.getvalue() - # If output exists, print it. - if output: - print(output) - return output - - -@pytest.fixture(scope="function") -def jp_configurable_serverapp( - jp_nbconvert_templates, # this fixture must preceed jp_environ - jp_environ, - jp_server_config, - jp_argv, - jp_http_port, - jp_base_url, - tmp_path, - jp_root_dir, - io_loop, - jp_logging_stream, -): - """Starts a Jupyter Server instance based on - the provided configuration values. - - The fixture is a factory; it can be called like - a function inside a unit test. Here's a basic - example of how use this fixture: - - .. code-block:: python - - def my_test(jp_configurable_serverapp): - - app = jp_configurable_serverapp(...) - ... - """ - ServerApp.clear_instance() - - def _configurable_serverapp( - config=jp_server_config, - base_url=jp_base_url, - argv=jp_argv, - environ=jp_environ, - http_port=jp_http_port, - tmp_path=tmp_path, - root_dir=jp_root_dir, - **kwargs - ): - c = Config(config) - c.NotebookNotary.db_file = ":memory:" - token = hexlify(os.urandom(4)).decode("ascii") - app = ServerApp.instance( - # Set the log level to debug for testing purposes - log_level="DEBUG", - port=http_port, - port_retries=0, - open_browser=False, - root_dir=str(root_dir), - base_url=base_url, - config=c, - allow_root=True, - token=token, - **kwargs - ) - - app.init_signal = lambda: None - app.log.propagate = True - app.log.handlers = [] - # Initialize app without httpserver - app.initialize(argv=argv, new_httpserver=False) - # Reroute all logging StreamHandlers away from stdin/stdout since pytest hijacks - # these streams and closes them at unfortunate times. - stream_handlers = [h for h in app.log.handlers if isinstance(h, logging.StreamHandler)] - for handler in stream_handlers: - handler.setStream(jp_logging_stream) - app.log.propagate = True - app.log.handlers = [] - # Start app without ioloop - app.start_app() - return app - - return _configurable_serverapp - - -@pytest.fixture -def jp_ensure_app_fixture(request): - """Ensures that the 'app' fixture used by pytest-tornasync - is set to `jp_web_app`, the Tornado Web Application returned - by the ServerApp in Jupyter Server, provided by the jp_web_app - fixture in this module. - - Note, this hardcodes the `app_fixture` option from - pytest-tornasync to `jp_web_app`. If this value is configured - to something other than the default, it will raise an exception. - """ - app_option = request.config.getoption("app_fixture") - if app_option not in ["app", "jp_web_app"]: - raise Exception( - "jp_serverapp requires the `app-fixture` option " - "to be set to 'jp_web_app`. Try rerunning the " - "current tests with the option `--app-fixture " - "jp_web_app`." - ) - elif app_option == "app": - # Manually set the app_fixture to `jp_web_app` if it's - # not set already. - request.config.option.app_fixture = "jp_web_app" - - -@pytest.fixture(scope="function") -def jp_serverapp(jp_ensure_app_fixture, jp_server_config, jp_argv, jp_configurable_serverapp): - """Starts a Jupyter Server instance based on the established configuration values.""" - app = jp_configurable_serverapp(config=jp_server_config, argv=jp_argv) - yield app - app.remove_server_info_file() - app.remove_browser_open_files() - - -@pytest.fixture -def jp_web_app(jp_serverapp): - """app fixture is needed by pytest_tornasync plugin""" - return jp_serverapp.web_app - - -@pytest.fixture -def jp_auth_header(jp_serverapp): - """Configures an authorization header using the token from the serverapp fixture.""" - return {"Authorization": "token {token}".format(token=jp_serverapp.token)} - - -@pytest.fixture -def jp_base_url(): - """Returns the base url to use for the test.""" - return "/a%40b/" - - -@pytest.fixture -def jp_fetch(jp_serverapp, http_server_client, jp_auth_header, jp_base_url): - """Sends an (asynchronous) HTTP request to a test server. - - The fixture is a factory; it can be called like - a function inside a unit test. Here's a basic - example of how use this fixture: - - .. code-block:: python - - async def my_test(jp_fetch): - - response = await jp_fetch("https://github.com/api", "spec.yaml") - ... - """ - - def client_fetch(*parts, headers=None, params=None, **kwargs): - if not headers: - headers = {} - if not params: - params = {} - # Handle URL strings - path_url = url_escape(url_path_join(*parts), plus=False) - base_path_url = url_path_join(jp_base_url, path_url) - params_url = urllib.parse.urlencode(params) - url = base_path_url + "?" + params_url - # Add auth keys to header - headers.update(jp_auth_header) - # Make request. - return http_server_client.fetch(url, headers=headers, request_timeout=20, **kwargs) - - return client_fetch - - -@pytest.fixture -def jp_ws_fetch(jp_serverapp, http_server_client, jp_auth_header, jp_http_port, jp_base_url): - """Sends a websocket request to a test server. - - The fixture is a factory; it can be called like - a function inside a unit test. Here's a basic - example of how use this fixture: - - .. code-block:: python - - async def my_test(jp_fetch, jp_ws_fetch): - # Start a kernel - r = await jp_fetch( - 'api', 'kernels', - method='POST', - body=json.dumps({ - 'name': "python3" - }) - ) - kid = json.loads(r.body.decode())['id'] - - # Open a websocket connection. - ws = await jp_ws_fetch( - 'api', 'kernels', kid, 'channels' - ) - ... - """ - - def client_fetch(*parts, headers=None, params=None, **kwargs): - if not headers: - headers = {} - if not params: - params = {} - # Handle URL strings - path_url = url_escape(url_path_join(*parts), plus=False) - base_path_url = url_path_join(jp_base_url, path_url) - urlparts = urllib.parse.urlparse("ws://localhost:{}".format(jp_http_port)) - urlparts = urlparts._replace(path=base_path_url, query=urllib.parse.urlencode(params)) - url = urlparts.geturl() - # Add auth keys to header - headers.update(jp_auth_header) - # Make request. - req = tornado.httpclient.HTTPRequest(url, headers=headers, connect_timeout=120) - return tornado.websocket.websocket_connect(req) - - return client_fetch - - -some_resource = "The very model of a modern major general" -sample_kernel_json = { - "argv": ["cat", "{connection_file}"], - "display_name": "Test kernel", -} - - -@pytest.fixture -def jp_kernelspecs(jp_data_dir): - """Configures some sample kernelspecs in the Jupyter data directory.""" - spec_names = ["sample", "sample 2", "bad"] - for name in spec_names: - sample_kernel_dir = jp_data_dir.joinpath("kernels", name) - sample_kernel_dir.mkdir(parents=True) - # Create kernel json file - sample_kernel_file = sample_kernel_dir.joinpath("kernel.json") - kernel_json = sample_kernel_json.copy() - if name == "bad": - kernel_json["argv"] = ["non_existent_path"] - sample_kernel_file.write_text(json.dumps(kernel_json)) - # Create resources text - sample_kernel_resources = sample_kernel_dir.joinpath("resource.txt") - sample_kernel_resources.write_text(some_resource) - - -@pytest.fixture(params=[True, False]) -def jp_contents_manager(request, tmp_path): - """Returns a FileContentsManager instance based on the use_atomic_writing parameter value.""" - return FileContentsManager(root_dir=str(tmp_path), use_atomic_writing=request.param) - - -@pytest.fixture -def jp_large_contents_manager(tmp_path): - """Returns a LargeFileManager instance.""" - return LargeFileManager(root_dir=str(tmp_path)) - - -@pytest.fixture -def jp_create_notebook(jp_root_dir): - """Creates a notebook in the test's home directory.""" - - def inner(nbpath): - nbpath = jp_root_dir.joinpath(nbpath) - # Check that the notebook has the correct file extension. - if nbpath.suffix != ".ipynb": - raise Exception("File extension for notebook must be .ipynb") - # If the notebook path has a parent directory, make sure it's created. - parent = nbpath.parent - parent.mkdir(parents=True, exist_ok=True) - # Create a notebook string and write to file. - nb = nbformat.v4.new_notebook() - nbtext = nbformat.writes(nb, version=4) - nbpath.write_text(nbtext) - - return inner - - -@pytest.fixture(autouse=True) -def jp_server_cleanup(): - yield - ServerApp.clear_instance() - - -@pytest.fixture -def jp_cleanup_subprocesses(jp_serverapp): - """Clean up subprocesses started by a Jupyter Server, i.e. kernels and terminal.""" - - async def _(): - terminal_cleanup = jp_serverapp.web_app.settings["terminal_manager"].terminate_all - kernel_cleanup = jp_serverapp.kernel_manager.shutdown_all - - async def kernel_cleanup_steps(): - # Try a graceful shutdown with a timeout - try: - await asyncio.wait_for(kernel_cleanup(), timeout=15.0) - except asyncio.TimeoutError: - # Now force a shutdown - try: - await asyncio.wait_for(kernel_cleanup(now=True), timeout=15.0) - except asyncio.TimeoutError: - print(Exception("Kernel never shutdown!")) - except Exception as e: - print(e) - - if asyncio.iscoroutinefunction(terminal_cleanup): - try: - await terminal_cleanup() - except Exception as e: - print(e) - else: - try: - await terminal_cleanup() - except Exception as e: - print(e) - if asyncio.iscoroutinefunction(kernel_cleanup): - await kernel_cleanup_steps() - else: - try: - kernel_cleanup() - except Exception as e: - print(e) - - return _ diff --git a/server/jupyter_server/serverapp.py b/server/jupyter_server/serverapp.py deleted file mode 100644 index c6b34ee..0000000 --- a/server/jupyter_server/serverapp.py +++ /dev/null @@ -1,2827 +0,0 @@ -# coding: utf-8 -"""A tornado based Jupyter server.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import binascii -import datetime -import errno -import gettext -import hashlib -import hmac -import inspect -import io -import ipaddress -import json -import logging -import mimetypes -import os -import pathlib -import random -import re -import select -import signal -import socket -import stat -import sys -import threading -import time -import urllib -import warnings -import webbrowser -from base64 import encodebytes - -try: - import resource -except ImportError: - # Windows - resource = None - -from jinja2 import Environment, FileSystemLoader - -from jupyter_core.paths import secure_write -from jupyter_server.transutils import trans, _i18n -from jupyter_server.utils import run_sync_in_loop, urljoin, pathname2url - -# the minimum viable tornado version: needs to be kept in sync with setup.py -MIN_TORNADO = (6, 1, 0) - -try: - import tornado - - assert tornado.version_info >= MIN_TORNADO -except (ImportError, AttributeError, AssertionError) as e: # pragma: no cover - raise ImportError(_i18n("The Jupyter Server requires tornado >=%s.%s.%s") % MIN_TORNADO) from e - -from tornado import httpserver -from tornado import ioloop -from tornado import web -from tornado.httputil import url_concat -from tornado.log import LogFormatter, app_log, access_log, gen_log - -if not sys.platform.startswith("win"): - from tornado.netutil import bind_unix_socket - -from jupyter_server import ( - DEFAULT_JUPYTER_SERVER_PORT, - DEFAULT_STATIC_FILES_PATH, - DEFAULT_TEMPLATE_PATH_LIST, - __version__, -) - -from jupyter_server.base.handlers import MainHandler, RedirectWithParams, Template404 -from jupyter_server.log import log_request -from jupyter_server.services.kernels.kernelmanager import ( - MappingKernelManager, - AsyncMappingKernelManager, -) -from jupyter_server.services.config import ConfigManager -from jupyter_server.services.contents.manager import ( - AsyncContentsManager, - ContentsManager, -) -from jupyter_server.services.contents.filemanager import ( - AsyncFileContentsManager, - FileContentsManager, -) -from jupyter_server.services.contents.largefilemanager import LargeFileManager -from jupyter_server.services.sessions.sessionmanager import SessionManager -from jupyter_server.gateway.managers import ( - GatewayMappingKernelManager, - GatewayKernelSpecManager, - GatewaySessionManager, - GatewayClient, -) -from jupyter_server.auth.authorizer import Authorizer, AllowAllAuthorizer - -from jupyter_server.auth.login import LoginHandler -from jupyter_server.auth.logout import LogoutHandler -from jupyter_server.base.handlers import FileFindHandler - -from traitlets.config import Config -from traitlets.config.application import catch_config_error, boolean_flag -from jupyter_core.application import ( - JupyterApp, - base_flags, - base_aliases, -) -from jupyter_core.paths import jupyter_config_path -from jupyter_client import KernelManager -from jupyter_client.kernelspec import KernelSpecManager -from jupyter_client.session import Session -from nbformat.sign import NotebookNotary -from traitlets import ( - Any, - Dict, - Unicode, - Integer, - List, - Bool, - Bytes, - Instance, - TraitError, - Type, - Float, - observe, - default, - validate, -) -from jupyter_core.paths import jupyter_runtime_dir -from jupyter_server._sysinfo import get_sys_info - -from jupyter_server._tz import utcnow -from jupyter_server.utils import ( - url_path_join, - check_pid, - url_escape, - pathname2url, - unix_socket_in_use, - urlencode_unix_socket_path, - fetch, -) - -from jupyter_server.extension.serverextension import ServerExtensionApp -from jupyter_server.extension.manager import ExtensionManager -from jupyter_server.extension.config import ExtensionConfigManager -from jupyter_server.traittypes import TypeFromClasses - -# Tolerate missing terminado package. -try: - from jupyter_server.terminal import TerminalManager - - terminado_available = True -except ImportError: - terminado_available = False - -# ----------------------------------------------------------------------------- -# Module globals -# ----------------------------------------------------------------------------- - -_examples = """ -jupyter server # start the server -jupyter server --certfile=mycert.pem # use SSL/TLS certificate -jupyter server password # enter a password to protect the server -""" - -JUPYTER_SERVICE_HANDLERS = dict( - auth=None, - api=["jupyter_server.services.api.handlers"], - config=["jupyter_server.services.config.handlers"], - contents=["jupyter_server.services.contents.handlers"], - files=["jupyter_server.files.handlers"], - kernels=["jupyter_server.services.kernels.handlers"], - kernelspecs=[ - "jupyter_server.kernelspecs.handlers", - "jupyter_server.services.kernelspecs.handlers", - ], - nbconvert=[ - "jupyter_server.nbconvert.handlers", - "jupyter_server.services.nbconvert.handlers", - ], - security=["jupyter_server.services.security.handlers"], - sessions=["jupyter_server.services.sessions.handlers"], - shutdown=["jupyter_server.services.shutdown"], - view=["jupyter_server.view.handlers"], -) - -# Added for backwards compatibility from classic notebook server. -DEFAULT_SERVER_PORT = DEFAULT_JUPYTER_SERVER_PORT - -# ----------------------------------------------------------------------------- -# Helper functions -# ----------------------------------------------------------------------------- - - -def random_ports(port, n): - """Generate a list of n random ports near the given port. - - The first 5 ports will be sequential, and the remaining n-5 will be - randomly selected in the range [port-2*n, port+2*n]. - """ - for i in range(min(5, n)): - yield port + i - for i in range(n - 5): - yield max(1, port + random.randint(-2 * n, 2 * n)) - - -def load_handlers(name): - """Load the (URL pattern, handler) tuples for each component.""" - mod = __import__(name, fromlist=["default_handlers"]) - return mod.default_handlers - - -# ----------------------------------------------------------------------------- -# The Tornado web application -# ----------------------------------------------------------------------------- - - -class ServerWebApplication(web.Application): - def __init__( - self, - jupyter_app, - default_services, - kernel_manager, - contents_manager, - session_manager, - kernel_spec_manager, - config_manager, - extra_services, - log, - base_url, - default_url, - settings_overrides, - jinja_env_options, - authorizer=None, - ): - if authorizer is None: - warnings.warn( - "authorizer unspecified. Using permissive AllowAllAuthorizer." - " Specify an authorizer to avoid this message.", - RuntimeWarning, - stacklevel=2, - ) - authorizer = AllowAllAuthorizer(jupyter_app) - - settings = self.init_settings( - jupyter_app, - kernel_manager, - contents_manager, - session_manager, - kernel_spec_manager, - config_manager, - extra_services, - log, - base_url, - default_url, - settings_overrides, - jinja_env_options, - authorizer=authorizer, - ) - handlers = self.init_handlers(default_services, settings) - - super(ServerWebApplication, self).__init__(handlers, **settings) - - def init_settings( - self, - jupyter_app, - kernel_manager, - contents_manager, - session_manager, - kernel_spec_manager, - config_manager, - extra_services, - log, - base_url, - default_url, - settings_overrides, - jinja_env_options=None, - authorizer=None, - ): - - _template_path = settings_overrides.get( - "template_path", - jupyter_app.template_file_path, - ) - if isinstance(_template_path, str): - _template_path = (_template_path,) - template_path = [os.path.expanduser(path) for path in _template_path] - - jenv_opt = {"autoescape": True} - jenv_opt.update(jinja_env_options if jinja_env_options else {}) - - env = Environment( - loader=FileSystemLoader(template_path), extensions=["jinja2.ext.i18n"], **jenv_opt - ) - sys_info = get_sys_info() - - # If the user is running the server in a git directory, make the assumption - # that this is a dev install and suggest to the developer `npm run build:watch`. - base_dir = os.path.realpath(os.path.join(__file__, "..", "..")) - dev_mode = os.path.exists(os.path.join(base_dir, ".git")) - - nbui = gettext.translation( - "nbui", - localedir=os.path.join(base_dir, "jupyter_server/i18n"), - fallback=True, - ) - env.install_gettext_translations(nbui, newstyle=False) - - if sys_info["commit_source"] == "repository": - # don't cache (rely on 304) when working from default branch - version_hash = "" - else: - # reset the cache on server restart - version_hash = datetime.datetime.now().strftime("%Y%m%d%H%M%S") - - now = utcnow() - - root_dir = contents_manager.root_dir - home = os.path.expanduser("~") - if root_dir.startswith(home + os.path.sep): - # collapse $HOME to ~ - root_dir = "~" + root_dir[len(home) :] - - settings = dict( - # basics - log_function=log_request, - base_url=base_url, - default_url=default_url, - template_path=template_path, - static_path=jupyter_app.static_file_path, - static_custom_path=jupyter_app.static_custom_path, - static_handler_class=FileFindHandler, - static_url_prefix=url_path_join(base_url, "/static/"), - static_handler_args={ - # don't cache custom.js - "no_cache_paths": [url_path_join(base_url, "static", "custom")], - }, - version_hash=version_hash, - # kernel message protocol over websoclet - kernel_ws_protocol=jupyter_app.kernel_ws_protocol, - # rate limits - limit_rate=jupyter_app.limit_rate, - iopub_msg_rate_limit=jupyter_app.iopub_msg_rate_limit, - iopub_data_rate_limit=jupyter_app.iopub_data_rate_limit, - rate_limit_window=jupyter_app.rate_limit_window, - # authentication - cookie_secret=jupyter_app.cookie_secret, - login_url=url_path_join(base_url, "/login"), - login_handler_class=jupyter_app.login_handler_class, - logout_handler_class=jupyter_app.logout_handler_class, - password=jupyter_app.password, - xsrf_cookies=True, - disable_check_xsrf=jupyter_app.disable_check_xsrf, - allow_remote_access=jupyter_app.allow_remote_access, - local_hostnames=jupyter_app.local_hostnames, - authenticate_prometheus=jupyter_app.authenticate_prometheus, - # managers - kernel_manager=kernel_manager, - contents_manager=contents_manager, - session_manager=session_manager, - kernel_spec_manager=kernel_spec_manager, - config_manager=config_manager, - authorizer=authorizer, - # handlers - extra_services=extra_services, - # Jupyter stuff - started=now, - # place for extensions to register activity - # so that they can prevent idle-shutdown - last_activity_times={}, - jinja_template_vars=jupyter_app.jinja_template_vars, - websocket_url=jupyter_app.websocket_url, - shutdown_button=jupyter_app.quit_button, - config=jupyter_app.config, - config_dir=jupyter_app.config_dir, - allow_password_change=jupyter_app.allow_password_change, - server_root_dir=root_dir, - jinja2_env=env, - terminals_available=terminado_available and jupyter_app.terminals_enabled, - serverapp=jupyter_app, - ) - - # allow custom overrides for the tornado web app. - settings.update(settings_overrides) - - if base_url and "xsrf_cookie_kwargs" not in settings: - # default: set xsrf cookie on base_url - settings["xsrf_cookie_kwargs"] = {"path": base_url} - return settings - - def init_handlers(self, default_services, settings): - """Load the (URL pattern, handler) tuples for each component.""" - # Order matters. The first handler to match the URL will handle the request. - handlers = [] - # load extra services specified by users before default handlers - for service in settings["extra_services"]: - handlers.extend(load_handlers(service)) - - # Add auth services. - if "auth" in default_services: - handlers.extend([(r"/login", settings["login_handler_class"])]) - handlers.extend([(r"/logout", settings["logout_handler_class"])]) - - # Load default services. Raise exception if service not - # found in JUPYTER_SERVICE_HANLDERS. - for service in default_services: - if service in JUPYTER_SERVICE_HANDLERS: - locations = JUPYTER_SERVICE_HANDLERS[service] - if locations is not None: - for loc in locations: - handlers.extend(load_handlers(loc)) - else: - raise Exception( - "{} is not recognized as a jupyter_server " - "service. If this is a custom service, " - "try adding it to the " - "`extra_services` list.".format(service) - ) - - # Add extra handlers from contents manager. - handlers.extend(settings["contents_manager"].get_extra_handlers()) - - # If gateway mode is enabled, replace appropriate handlers to perform redirection - if GatewayClient.instance().gateway_enabled: - # for each handler required for gateway, locate its pattern - # in the current list and replace that entry... - gateway_handlers = load_handlers("jupyter_server.gateway.handlers") - for i, gwh in enumerate(gateway_handlers): - for j, h in enumerate(handlers): - if gwh[0] == h[0]: - handlers[j] = (gwh[0], gwh[1]) - break - - # register base handlers last - handlers.extend(load_handlers("jupyter_server.base.handlers")) - - if settings["default_url"] != settings["base_url"]: - # set the URL that will be redirected from `/` - handlers.append( - ( - r"/?", - RedirectWithParams, - { - "url": settings["default_url"], - "permanent": False, # want 302, not 301 - }, - ) - ) - else: - handlers.append((r"/", MainHandler)) - - # prepend base_url onto the patterns that we match - new_handlers = [] - for handler in handlers: - pattern = url_path_join(settings["base_url"], handler[0]) - new_handler = tuple([pattern] + list(handler[1:])) - new_handlers.append(new_handler) - # add 404 on the end, which will catch everything that falls through - new_handlers.append((r"(.*)", Template404)) - return new_handlers - - def last_activity(self): - """Get a UTC timestamp for when the server last did something. - - Includes: API activity, kernel activity, kernel shutdown, and terminal - activity. - """ - sources = [ - self.settings["started"], - self.settings["kernel_manager"].last_kernel_activity, - ] - try: - sources.append(self.settings["api_last_activity"]) - except KeyError: - pass - try: - sources.append(self.settings["terminal_last_activity"]) - except KeyError: - pass - sources.extend(self.settings["last_activity_times"].values()) - return max(sources) - - -class JupyterPasswordApp(JupyterApp): - """Set a password for the Jupyter server. - - Setting a password secures the Jupyter server - and removes the need for token-based authentication. - """ - - description = __doc__ - - def _config_file_default(self): - return os.path.join(self.config_dir, "jupyter_server_config.json") - - def start(self): - from jupyter_server.auth.security import set_password - - set_password(config_file=self.config_file) - self.log.info("Wrote hashed password to %s" % self.config_file) - - -def shutdown_server(server_info, timeout=5, log=None): - """Shutdown a Jupyter server in a separate process. - - *server_info* should be a dictionary as produced by list_running_servers(). - - Will first try to request shutdown using /api/shutdown . - On Unix, if the server is still running after *timeout* seconds, it will - send SIGTERM. After another timeout, it escalates to SIGKILL. - - Returns True if the server was stopped by any means, False if stopping it - failed (on Windows). - """ - - url = server_info["url"] - pid = server_info["pid"] - - if log: - log.debug("POST request to %sapi/shutdown", url) - - r = fetch(url, method="POST", headers={"Authorization": "token " + server_info["token"]}) - # Poll to see if it shut down. - for _ in range(timeout * 10): - if not check_pid(pid): - if log: - log.debug("Server PID %s is gone", pid) - return True - time.sleep(0.1) - - if sys.platform.startswith("win"): - return False - - if log: - log.debug("SIGTERM to PID %s", pid) - os.kill(pid, signal.SIGTERM) - - # Poll to see if it shut down. - for _ in range(timeout * 10): - if not check_pid(pid): - if log: - log.debug("Server PID %s is gone", pid) - return True - time.sleep(0.1) - - if log: - log.debug("SIGKILL to PID %s", pid) - os.kill(pid, signal.SIGKILL) - return True # SIGKILL cannot be caught - - -class JupyterServerStopApp(JupyterApp): - - version = __version__ - description = "Stop currently running Jupyter server for a given port" - - port = Integer( - DEFAULT_JUPYTER_SERVER_PORT, - config=True, - help="Port of the server to be killed. Default %s" % DEFAULT_JUPYTER_SERVER_PORT, - ) - - sock = Unicode("", config=True, help="UNIX socket of the server to be killed.") - - def parse_command_line(self, argv=None): - super(JupyterServerStopApp, self).parse_command_line(argv) - if self.extra_args: - try: - self.port = int(self.extra_args[0]) - except ValueError: - # self.extra_args[0] was not an int, so it must be a string (unix socket). - self.sock = self.extra_args[0] - - def shutdown_server(self, server): - return shutdown_server(server, log=self.log) - - def _shutdown_or_exit(self, target_endpoint, server): - print("Shutting down server on %s..." % target_endpoint) - if not self.shutdown_server(server): - sys.exit("Could not stop server on %s" % target_endpoint) - - @staticmethod - def _maybe_remove_unix_socket(socket_path): - try: - os.unlink(socket_path) - except (OSError, IOError): - pass - - def start(self): - servers = list(list_running_servers(self.runtime_dir, log=self.log)) - if not servers: - self.exit("There are no running servers (per %s)" % self.runtime_dir) - for server in servers: - if self.sock: - sock = server.get("sock", None) - if sock and sock == self.sock: - self._shutdown_or_exit(sock, server) - # Attempt to remove the UNIX socket after stopping. - self._maybe_remove_unix_socket(sock) - return - elif self.port: - port = server.get("port", None) - if port == self.port: - self._shutdown_or_exit(port, server) - return - current_endpoint = self.sock or self.port - print( - "There is currently no server running on {}".format(current_endpoint), - file=sys.stderr, - ) - print("Ports/sockets currently in use:", file=sys.stderr) - for server in servers: - print(" - {}".format(server.get("sock") or server["port"]), file=sys.stderr) - self.exit(1) - - -class JupyterServerListApp(JupyterApp): - version = __version__ - description = _i18n("List currently running Kennen servers.") - - flags = dict( - jsonlist=( - {"JupyterServerListApp": {"jsonlist": True}}, - _i18n("Produce machine-readable JSON list output."), - ), - json=( - {"JupyterServerListApp": {"json": True}}, - _i18n("Produce machine-readable JSON object on each line of output."), - ), - ) - - jsonlist = Bool( - False, - config=True, - help=_i18n( - "If True, the output will be a JSON list of objects, one per " - "active Kennen server, each with the details from the " - "relevant server info file." - ), - ) - json = Bool( - False, - config=True, - help=_i18n( - "If True, each line of output will be a JSON object with the " - "details from the server info file. For a JSON list output, " - "see the KennenServerListApp.jsonlist configuration value" - ), - ) - - def start(self): - serverinfo_list = list(list_running_servers(self.runtime_dir, log=self.log)) - if self.jsonlist: - print(json.dumps(serverinfo_list, indent=2)) - elif self.json: - for serverinfo in serverinfo_list: - print(json.dumps(serverinfo)) - else: - print("Currently running servers:") - for serverinfo in serverinfo_list: - url = serverinfo["url"] - if serverinfo.get("token"): - url = url + "?token=%s" % serverinfo["token"] - print(url, "::", serverinfo["root_dir"]) - - -# ----------------------------------------------------------------------------- -# Aliases and Flags -# ----------------------------------------------------------------------------- - -flags = dict(base_flags) - -flags["allow-root"] = ( - {"ServerApp": {"allow_root": True}}, - _i18n("Allow the server to be run from root user."), -) -flags["no-browser"] = ( - {"ServerApp": {"open_browser": False}, "ExtensionApp": {"open_browser": False}}, - _i18n("Prevent the opening of the default url in the browser."), -) -flags["debug"] = ( - {"ServerApp": {"log_level": "DEBUG"}, "ExtensionApp": {"log_level": "DEBUG"}}, - _i18n("Set debug level for the extension and underlying server applications."), -) -flags["autoreload"] = ( - {"ServerApp": {"autoreload": True}}, - """Autoreload the webapp - Enable reloading of the tornado webapp and all imported Python packages - when any changes are made to any Python src files in server or - extensions. - """, -) - - -# Add notebook manager flags -flags.update( - boolean_flag( - "script", - "FileContentsManager.save_script", - "DEPRECATED, IGNORED", - "DEPRECATED, IGNORED", - ) -) - -aliases = dict(base_aliases) - -aliases.update( - { - "ip": "ServerApp.ip", - "port": "ServerApp.port", - "port-retries": "ServerApp.port_retries", - "sock": "ServerApp.sock", - "sock-mode": "ServerApp.sock_mode", - "transport": "KernelManager.transport", - "keyfile": "ServerApp.keyfile", - "certfile": "ServerApp.certfile", - "client-ca": "ServerApp.client_ca", - "notebook-dir": "ServerApp.root_dir", - "preferred-dir": "ServerApp.preferred_dir", - "browser": "ServerApp.browser", - "pylab": "ServerApp.pylab", - "gateway-url": "GatewayClient.url", - } -) - -# ----------------------------------------------------------------------------- -# ServerApp -# ----------------------------------------------------------------------------- - - -class ServerApp(JupyterApp): - - name = "jupyter-server" - version = __version__ - description = _i18n( - """The Kennen Server. - - This launches a Tornado-based Kennen Server.""" - ) - examples = _examples - - flags = Dict(flags) - aliases = Dict(aliases) - - classes = [ - KernelManager, - Session, - MappingKernelManager, - KernelSpecManager, - AsyncMappingKernelManager, - ContentsManager, - FileContentsManager, - AsyncContentsManager, - AsyncFileContentsManager, - NotebookNotary, - GatewayMappingKernelManager, - GatewayKernelSpecManager, - GatewaySessionManager, - GatewayClient, - Authorizer, - ] - if terminado_available: # Only necessary when terminado is available - classes.append(TerminalManager) - - subcommands = dict( - list=(JupyterServerListApp, JupyterServerListApp.description.splitlines()[0]), - stop=(JupyterServerStopApp, JupyterServerStopApp.description.splitlines()[0]), - password=(JupyterPasswordApp, JupyterPasswordApp.description.splitlines()[0]), - extension=(ServerExtensionApp, ServerExtensionApp.description.splitlines()[0]), - ) - - # A list of services whose handlers will be exposed. - # Subclasses can override this list to - # expose a subset of these handlers. - default_services = ( - "api", - "auth", - "config", - "contents", - "files", - "kernels", - "kernelspecs", - "nbconvert", - "security", - "sessions", - "shutdown", - "view", - ) - - _log_formatter_cls = LogFormatter - - @default("log_level") - def _default_log_level(self): - return logging.INFO - - @default("log_format") - def _default_log_format(self): - """override default log format to include date & time""" - return ( - "%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s]%(end_color)s %(message)s" - ) - - # file to be opened in the Jupyter server - file_to_run = Unicode("", help="Open the named file when the application is launched.").tag( - config=True - ) - - file_url_prefix = Unicode( - "notebooks", help="The URL prefix where files are opened directly." - ).tag(config=True) - - # Network related information - allow_origin = Unicode( - "", - config=True, - help="""Set the Access-Control-Allow-Origin header - - Use '*' to allow any origin to access your server. - - Takes precedence over allow_origin_pat. - """, - ) - - allow_origin_pat = Unicode( - "", - config=True, - help="""Use a regular expression for the Access-Control-Allow-Origin header - - Requests from an origin matching the expression will get replies with: - - Access-Control-Allow-Origin: origin - - where `origin` is the origin of the request. - - Ignored if allow_origin is set. - """, - ) - - allow_credentials = Bool( - False, - config=True, - help=_i18n("Set the Access-Control-Allow-Credentials: true header"), - ) - - allow_root = Bool( - False, - config=True, - help=_i18n("Whether to allow the user to run the server as root."), - ) - - autoreload = Bool( - False, - config=True, - help=_i18n("Reload the webapp when changes are made to any Python src files."), - ) - - default_url = Unicode("/", config=True, help=_i18n("The default URL to redirect to from `/`")) - - ip = Unicode( - "localhost", - config=True, - help=_i18n("The IP address the Jupyter server will listen on."), - ) - - @default("ip") - def _default_ip(self): - """Return localhost if available, 127.0.0.1 otherwise. - - On some (horribly broken) systems, localhost cannot be bound. - """ - s = socket.socket() - try: - s.bind(("localhost", 0)) - except socket.error as e: - self.log.warning( - _i18n("Cannot bind to localhost, using 127.0.0.1 as default ip\n%s"), e - ) - return "127.0.0.1" - else: - s.close() - return "localhost" - - @validate("ip") - def _validate_ip(self, proposal): - value = proposal["value"] - if value == "*": - value = "" - return value - - custom_display_url = Unicode( - "", - config=True, - help=_i18n( - """Override URL shown to users. - - Replace actual URL, including protocol, address, port and base URL, - with the given value when displaying URL to the users. Do not change - the actual connection URL. If authentication token is enabled, the - token is added to the custom URL automatically. - - This option is intended to be used when the URL to display to the user - cannot be determined reliably by the Jupyter server (proxified - or containerized setups for example).""" - ), - ) - - port_env = "JUPYTER_PORT" - port_default_value = DEFAULT_JUPYTER_SERVER_PORT - - port = Integer( - config=True, - help=_i18n("The port the server will listen on (env: JUPYTER_PORT)."), - ) - - @default("port") - def port_default(self): - return int(os.getenv(self.port_env, self.port_default_value)) - - port_retries_env = "JUPYTER_PORT_RETRIES" - port_retries_default_value = 50 - port_retries = Integer( - port_retries_default_value, - config=True, - help=_i18n( - "The number of additional ports to try if the specified port is not " - "available (env: JUPYTER_PORT_RETRIES)." - ), - ) - - @default("port_retries") - def port_retries_default(self): - return int(os.getenv(self.port_retries_env, self.port_retries_default_value)) - - sock = Unicode("", config=True, help="The UNIX socket the Jupyter server will listen on.") - - sock_mode = Unicode( - "0600", - config=True, - help="The permissions mode for UNIX socket creation (default: 0600).", - ) - - @validate("sock_mode") - def _validate_sock_mode(self, proposal): - value = proposal["value"] - try: - converted_value = int(value.encode(), 8) - assert all( - ( - # Ensure the mode is at least user readable/writable. - bool(converted_value & stat.S_IRUSR), - bool(converted_value & stat.S_IWUSR), - # And isn't out of bounds. - converted_value <= 2**12, - ) - ) - except ValueError: - raise TraitError('invalid --sock-mode value: %s, please specify as e.g. "0600"' % value) - except AssertionError: - raise TraitError( - "invalid --sock-mode value: %s, must have u+rw (0600) at a minimum" % value - ) - return value - - certfile = Unicode( - "", - config=True, - help=_i18n("""The full path to an SSL/TLS certificate file."""), - ) - - keyfile = Unicode( - "", - config=True, - help=_i18n("""The full path to a private key file for usage with SSL/TLS."""), - ) - - client_ca = Unicode( - "", - config=True, - help=_i18n( - """The full path to a certificate authority certificate for SSL/TLS client authentication.""" - ), - ) - - cookie_secret_file = Unicode( - config=True, help=_i18n("""The file where the cookie secret is stored.""") - ) - - @default("cookie_secret_file") - def _default_cookie_secret_file(self): - return os.path.join(self.runtime_dir, "jupyter_cookie_secret") - - cookie_secret = Bytes( - b"", - config=True, - help="""The random bytes used to secure cookies. - By default this is a new random number every time you start the server. - Set it to a value in a config file to enable logins to persist across server sessions. - - Note: Cookie secrets should be kept private, do not share config files with - cookie_secret stored in plaintext (you can read the value from a file). - """, - ) - - @default("cookie_secret") - def _default_cookie_secret(self): - if os.path.exists(self.cookie_secret_file): - with io.open(self.cookie_secret_file, "rb") as f: - key = f.read() - else: - key = encodebytes(os.urandom(32)) - self._write_cookie_secret_file(key) - h = hmac.new(key, digestmod=hashlib.sha256) - h.update(self.password.encode()) - return h.digest() - - def _write_cookie_secret_file(self, secret): - """write my secret to my secret_file""" - self.log.info(_i18n("Writing Jupyter server cookie secret to %s"), self.cookie_secret_file) - try: - with secure_write(self.cookie_secret_file, True) as f: - f.write(secret) - except OSError as e: - self.log.error( - _i18n("Failed to write cookie secret to %s: %s"), - self.cookie_secret_file, - e, - ) - - token = Unicode( - "", - help=_i18n( - """Token used for authenticating first-time connections to the server. - - The token can be read from the file referenced by JUPYTER_TOKEN_FILE or set directly - with the JUPYTER_TOKEN environment variable. - - When no password is enabled, - the default is to generate a new, random token. - - Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED. - """ - ), - ).tag(config=True) - - _token_generated = True - - @default("token") - def _token_default(self): - if os.getenv("JUPYTER_TOKEN"): - self._token_generated = False - return os.getenv("JUPYTER_TOKEN") - if os.getenv("JUPYTER_TOKEN_FILE"): - self._token_generated = False - with io.open(os.getenv("JUPYTER_TOKEN_FILE"), "r") as token_file: - return token_file.read() - if self.password: - # no token if password is enabled - self._token_generated = False - return "" - else: - self._token_generated = True - return binascii.hexlify(os.urandom(24)).decode("ascii") - - min_open_files_limit = Integer( - config=True, - help=""" - Gets or sets a lower bound on the open file handles process resource - limit. This may need to be increased if you run into an - OSError: [Errno 24] Too many open files. - This is not applicable when running on Windows. - """, - allow_none=True, - ) - - @default("min_open_files_limit") - def _default_min_open_files_limit(self): - if resource is None: - # Ignoring min_open_files_limit because the limit cannot be adjusted (for example, on Windows) - return None - - soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) - - DEFAULT_SOFT = 4096 - if hard >= DEFAULT_SOFT: - return DEFAULT_SOFT - - self.log.debug( - "Default value for min_open_files_limit is ignored (hard=%r, soft=%r)", - hard, - soft, - ) - - return soft - - max_body_size = Integer( - 512 * 1024 * 1024, - config=True, - help=""" - Sets the maximum allowed size of the client request body, specified in - the Content-Length request header field. If the size in a request - exceeds the configured value, a malformed HTTP message is returned to - the client. - - Note: max_body_size is applied even in streaming mode. - """, - ) - - max_buffer_size = Integer( - 512 * 1024 * 1024, - config=True, - help=""" - Gets or sets the maximum amount of memory, in bytes, that is allocated - for use by the buffer manager. - """, - ) - - @observe("token") - def _token_changed(self, change): - self._token_generated = False - - password = Unicode( - "", - config=True, - help="""Hashed password to use for web authentication. - - To generate, type in a python/IPython shell: - - from jupyter_server.auth import passwd; passwd() - - The string should be of the form type:salt:hashed-password. - """, - ) - - password_required = Bool( - False, - config=True, - help="""Forces users to use a password for the Jupyter server. - This is useful in a multi user environment, for instance when - everybody in the LAN can access each other's machine through ssh. - - In such a case, serving on localhost is not secure since - any user can connect to the Jupyter server via ssh. - - """, - ) - - allow_password_change = Bool( - True, - config=True, - help="""Allow password to be changed at login for the Jupyter server. - - While logging in with a token, the Jupyter server UI will give the opportunity to - the user to enter a new password at the same time that will replace - the token login mechanism. - - This can be set to false to prevent changing password from the UI/API. - """, - ) - - disable_check_xsrf = Bool( - False, - config=True, - help="""Disable cross-site-request-forgery protection - - Jupyter notebook 4.3.1 introduces protection from cross-site request forgeries, - requiring API requests to either: - - - originate from pages served by this server (validated with XSRF cookie and token), or - - authenticate with a token - - Some anonymous compute resources still desire the ability to run code, - completely without authentication. - These services can disable all authentication and security checks, - with the full knowledge of what that implies. - """, - ) - - allow_remote_access = Bool( - config=True, - help="""Allow requests where the Host header doesn't point to a local server - - By default, requests get a 403 forbidden response if the 'Host' header - shows that the browser thinks it's on a non-local domain. - Setting this option to True disables this check. - - This protects against 'DNS rebinding' attacks, where a remote web server - serves you a page and then changes its DNS to send later requests to a - local IP, bypassing same-origin checks. - - Local IP addresses (such as 127.0.0.1 and ::1) are allowed as local, - along with hostnames configured in local_hostnames. - """, - ) - - @default("allow_remote_access") - def _default_allow_remote(self): - """Disallow remote access if we're listening only on loopback addresses""" - - # if blank, self.ip was configured to "*" meaning bind to all interfaces, - # see _valdate_ip - if self.ip == "": - return True - - try: - addr = ipaddress.ip_address(self.ip) - except ValueError: - # Address is a hostname - for info in socket.getaddrinfo(self.ip, self.port, 0, socket.SOCK_STREAM): - addr = info[4][0] - - try: - parsed = ipaddress.ip_address(addr.split("%")[0]) - except ValueError: - self.log.warning("Unrecognised IP address: %r", addr) - continue - - # Macs map localhost to 'fe80::1%lo0', a link local address - # scoped to the loopback interface. For now, we'll assume that - # any scoped link-local address is effectively local. - if not (parsed.is_loopback or (("%" in addr) and parsed.is_link_local)): - return True - return False - else: - return not addr.is_loopback - - use_redirect_file = Bool( - True, - config=True, - help="""Disable launching browser by redirect file - For versions of notebook > 5.7.2, a security feature measure was added that - prevented the authentication token used to launch the browser from being visible. - This feature makes it difficult for other users on a multi-user system from - running code in your Jupyter session as you. - However, some environments (like Windows Subsystem for Linux (WSL) and Chromebooks), - launching a browser using a redirect file can lead the browser failing to load. - This is because of the difference in file structures/paths between the runtime and - the browser. - - Disabling this setting to False will disable this behavior, allowing the browser - to launch by using a URL and visible token (as before). - """, - ) - - local_hostnames = List( - Unicode(), - ["localhost"], - config=True, - help="""Hostnames to allow as local when allow_remote_access is False. - - Local IP addresses (such as 127.0.0.1 and ::1) are automatically accepted - as local as well. - """, - ) - - open_browser = Bool( - False, - config=True, - help="""Whether to open in a browser after starting. - The specific browser used is platform dependent and - determined by the python standard library `webbrowser` - module, unless it is overridden using the --browser - (ServerApp.browser) configuration option. - """, - ) - - browser = Unicode( - "", - config=True, - help="""Specify what command to use to invoke a web - browser when starting the server. If not specified, the - default browser will be determined by the `webbrowser` - standard library module, which allows setting of the - BROWSER environment variable to override it. - """, - ) - - webbrowser_open_new = Integer( - 2, - config=True, - help=_i18n( - """Specify where to open the server on startup. This is the - `new` argument passed to the standard library method `webbrowser.open`. - The behaviour is not guaranteed, but depends on browser support. Valid - values are: - - - 2 opens a new tab, - - 1 opens a new window, - - 0 opens in an existing window. - - See the `webbrowser.open` documentation for details. - """ - ), - ) - - tornado_settings = Dict( - config=True, - help=_i18n( - "Supply overrides for the tornado.web.Application that the " "Jupyter server uses." - ), - ) - - websocket_compression_options = Any( - None, - config=True, - help=_i18n( - """ - Set the tornado compression options for websocket connections. - - This value will be returned from :meth:`WebSocketHandler.get_compression_options`. - None (default) will disable compression. - A dict (even an empty one) will enable compression. - - See the tornado docs for WebSocketHandler.get_compression_options for details. - """ - ), - ) - terminado_settings = Dict( - config=True, - help=_i18n('Supply overrides for terminado. Currently only supports "shell_command".'), - ) - - cookie_options = Dict( - config=True, - help=_i18n( - "Extra keyword arguments to pass to `set_secure_cookie`." - " See tornado's set_secure_cookie docs for details." - ), - ) - get_secure_cookie_kwargs = Dict( - config=True, - help=_i18n( - "Extra keyword arguments to pass to `get_secure_cookie`." - " See tornado's get_secure_cookie docs for details." - ), - ) - ssl_options = Dict( - allow_none=True, - config=True, - help=_i18n( - """Supply SSL options for the tornado HTTPServer. - See the tornado docs for details.""" - ), - ) - - jinja_environment_options = Dict( - config=True, - help=_i18n("Supply extra arguments that will be passed to Jinja environment."), - ) - - jinja_template_vars = Dict( - config=True, - help=_i18n("Extra variables to supply to jinja templates when rendering."), - ) - - base_url = Unicode( - "/", - config=True, - help="""The base URL for the Jupyter server. - - Leading and trailing slashes can be omitted, - and will automatically be added. - """, - ) - - @validate("base_url") - def _update_base_url(https://github.com/self,%20proposal): - value = proposal["value"] - if not value.startswith("/"): - value = "/" + value - if not value.endswith("/"): - value = value + "/" - return value - - extra_static_paths = List( - Unicode(), - config=True, - help="""Extra paths to search for serving static files. - - This allows adding javascript/css to be available from the Jupyter server machine, - or overriding individual files in the IPython""", - ) - - @property - def static_file_path(self): - """return extra paths + the default location""" - return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH] - - static_custom_path = List(Unicode(), help=_i18n("""Path to search for custom.js, css""")) - - @default("static_custom_path") - def _default_static_custom_path(self): - return [os.path.join(d, "custom") for d in (self.config_dir, DEFAULT_STATIC_FILES_PATH)] - - extra_template_paths = List( - Unicode(), - config=True, - help=_i18n( - """Extra paths to search for serving jinja templates. - - Can be used to override templates from jupyter_server.templates.""" - ), - ) - - @property - def template_file_path(self): - """return extra paths + the default locations""" - return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST - - extra_services = List( - Unicode(), - config=True, - help=_i18n( - """handlers that should be loaded at higher priority than the default services""" - ), - ) - - websocket_url = Unicode( - "", - config=True, - help="""The base URL for websockets, - if it differs from the HTTP server (hint: it almost certainly doesn't). - - Should be in the form of an HTTP origin: ws[s]://hostname[:port] - """, - ) - - quit_button = Bool( - True, - config=True, - help="""If True, display controls to shut down the Jupyter server, such as menu items or buttons.""", - ) - - # REMOVE in VERSION 2.0 - # Temporarily allow content managers to inherit from the 'notebook' - # package. We will deprecate this in the next major release. - contents_manager_class = TypeFromClasses( - default_value=LargeFileManager, - klasses=[ - "jupyter_server.services.contents.manager.ContentsManager", - "notebook.services.contents.manager.ContentsManager", - ], - config=True, - help=_i18n("The content manager class to use."), - ) - - # Throws a deprecation warning to notebook based contents managers. - @observe("contents_manager_class") - def _observe_contents_manager_class(self, change): - new = change["new"] - # If 'new' is a class, get a string representing the import - # module path. - if inspect.isclass(new): - new = new.__module__ - - if new.startswith("notebook"): - self.log.warning( - "The specified 'contents_manager_class' class inherits a manager from the " - "'notebook' package. This is not guaranteed to work in future " - "releases of Jupyter Server. Instead, consider switching the " - "manager to inherit from the 'jupyter_server' managers. " - "Jupyter Server will temporarily allow 'notebook' managers " - "until its next major release (2.x)." - ) - - kernel_manager_class = Type( - default_value=AsyncMappingKernelManager, - klass=MappingKernelManager, - config=True, - help=_i18n("The kernel manager class to use."), - ) - - session_manager_class = Type( - default_value=SessionManager, - config=True, - help=_i18n("The session manager class to use."), - ) - - config_manager_class = Type( - default_value=ConfigManager, - config=True, - help=_i18n("The config manager class to use"), - ) - - kernel_spec_manager = Instance(KernelSpecManager, allow_none=True) - - kernel_spec_manager_class = Type( - default_value=KernelSpecManager, - config=True, - help=""" - The kernel spec manager class to use. Should be a subclass - of `jupyter_client.kernelspec.KernelSpecManager`. - - The Api of KernelSpecManager is provisional and might change - without warning between this version of Jupyter and the next stable one. - """, - ) - - login_handler_class = Type( - default_value=LoginHandler, - klass=web.RequestHandler, - config=True, - help=_i18n("The login handler class to use."), - ) - - logout_handler_class = Type( - default_value=LogoutHandler, - klass=web.RequestHandler, - config=True, - help=_i18n("The logout handler class to use."), - ) - - authorizer_class = Type( - default_value=AllowAllAuthorizer, - klass=Authorizer, - config=True, - help=_i18n("The authorizer class to use."), - ) - - trust_xheaders = Bool( - False, - config=True, - help=( - _i18n( - "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers" - "sent by the upstream reverse proxy. Necessary if the proxy handles SSL" - ) - ), - ) - - info_file = Unicode() - - @default("info_file") - def _default_info_file(self): - info_file = "jpserver-%s.json" % os.getpid() - return os.path.join(self.runtime_dir, info_file) - - browser_open_file = Unicode() - - @default("browser_open_file") - def _default_browser_open_file(self): - basename = "jpserver-%s-open.html" % os.getpid() - return os.path.join(self.runtime_dir, basename) - - browser_open_file_to_run = Unicode() - - @default("browser_open_file_to_run") - def _default_browser_open_file_to_run(self): - basename = "jpserver-file-to-run-%s-open.html" % os.getpid() - return os.path.join(self.runtime_dir, basename) - - pylab = Unicode( - "disabled", - config=True, - help=_i18n( - """ - DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib. - """ - ), - ) - - @observe("pylab") - def _update_pylab(self, change): - """when --pylab is specified, display a warning and exit""" - if change["new"] != "warn": - backend = " %s" % change["new"] - else: - backend = "" - self.log.error( - _i18n("Support for specifying --pylab on the command line has been removed.") - ) - self.log.error( - _i18n("Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself.").format( - backend - ) - ) - self.exit(1) - - notebook_dir = Unicode(config=True, help=_i18n("DEPRECATED, use root_dir.")) - - @observe("notebook_dir") - def _update_notebook_dir(self, change): - if self._root_dir_set: - # only use deprecated config if new config is not set - return - self.log.warning(_i18n("notebook_dir is deprecated, use root_dir")) - self.root_dir = change["new"] - - root_dir = Unicode(config=True, help=_i18n("The directory to use for notebooks and kernels.")) - _root_dir_set = False - - @default("root_dir") - def _default_root_dir(self): - if self.file_to_run: - self._root_dir_set = True - return os.path.dirname(os.path.abspath(self.file_to_run)) - else: - return os.getcwd() - - def _normalize_dir(self, value): - # Strip any trailing slashes - # *except* if it's root - _, path = os.path.splitdrive(value) - if path == os.sep: - return value - value = value.rstrip(os.sep) - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - return value - - @validate("root_dir") - def _root_dir_validate(self, proposal): - value = self._normalize_dir(proposal["value"]) - if not os.path.isdir(value): - raise TraitError(trans.gettext("No such directory: '%r'") % value) - return value - - preferred_dir = Unicode( - config=True, - help=trans.gettext("Preferred starting directory to use for notebooks and kernels."), - ) - - @default("preferred_dir") - def _default_prefered_dir(self): - return self.root_dir - - @validate("preferred_dir") - def _preferred_dir_validate(self, proposal): - value = self._normalize_dir(proposal["value"]) - if not os.path.isdir(value): - raise TraitError(trans.gettext("No such preferred dir: '%r'") % value) - - # preferred_dir must be equal or a subdir of root_dir - if not value.startswith(self.root_dir): - raise TraitError( - trans.gettext("preferred_dir must be equal or a subdir of root_dir: '%r'") % value - ) - - return value - - @observe("root_dir") - def _root_dir_changed(self, change): - self._root_dir_set = True - if not self.preferred_dir.startswith(change["new"]): - self.log.warning( - trans.gettext("Value of preferred_dir updated to use value of root_dir") - ) - self.preferred_dir = change["new"] - - @observe("server_extensions") - def _update_server_extensions(self, change): - self.log.warning(_i18n("server_extensions is deprecated, use jpserver_extensions")) - self.server_extensions = change["new"] - - jpserver_extensions = Dict( - default_value={}, - value_trait=Bool(), - config=True, - help=( - _i18n( - "Dict of Python modules to load as Jupyter server extensions." - "Entry values can be used to enable and disable the loading of" - "the extensions. The extensions will be loaded in alphabetical " - "order." - ) - ), - ) - - reraise_server_extension_failures = Bool( - False, - config=True, - help=_i18n("Reraise exceptions encountered loading server extensions?"), - ) - - kernel_ws_protocol = Unicode( - None, - allow_none=True, - config=True, - help=_i18n( - "Preferred kernel message protocol over websocket to use (default: None). " - "If an empty string is passed, select the legacy protocol. If None, " - "the selected protocol will depend on what the front-end supports " - "(usually the most recent protocol supported by the back-end and the " - "front-end)." - ), - ) - - limit_rate = Bool( - True, - config=True, - help=_i18n( - "Whether to limit the rate of IOPub messages (default: True). " - "If True, use iopub_msg_rate_limit, iopub_data_rate_limit and/or rate_limit_window " - "to tune the rate." - ), - ) - - iopub_msg_rate_limit = Float( - 1000, - config=True, - help=_i18n( - """(msgs/sec) - Maximum rate at which messages can be sent on iopub before they are - limited.""" - ), - ) - - iopub_data_rate_limit = Float( - 1000000, - config=True, - help=_i18n( - """(bytes/sec) - Maximum rate at which stream output can be sent on iopub before they are - limited.""" - ), - ) - - rate_limit_window = Float( - 3, - config=True, - help=_i18n( - """(sec) Time window used to - check the message and data rate limits.""" - ), - ) - - shutdown_no_activity_timeout = Integer( - 0, - config=True, - help=( - "Shut down the server after N seconds with no kernels or " - "terminals running and no activity. " - "This can be used together with culling idle kernels " - "(MappingKernelManager.cull_idle_timeout) to " - "shutdown the Jupyter server when it's not in use. This is not " - "precisely timed: it may shut down up to a minute later. " - "0 (the default) disables this automatic shutdown." - ), - ) - - terminals_enabled = Bool( - True, - config=True, - help=_i18n( - """Set to False to disable terminals. - - This does *not* make the server more secure by itself. - Anything the user can in a terminal, they can also do in a notebook. - - Terminals may also be automatically disabled if the terminado package - is not available. - """ - ), - ) - - # Since use of terminals is also a function of whether the terminado package is - # available, this variable holds the "final indication" of whether terminal functionality - # should be considered (particularly during shutdown/cleanup). It is enabled only - # once both the terminals "service" can be initialized and terminals_enabled is True. - # Note: this variable is slightly different from 'terminals_available' in the web settings - # in that this variable *could* remain false if terminado is available, yet the terminal - # service's initialization still fails. As a result, this variable holds the truth. - terminals_available = False - - authenticate_prometheus = Bool( - True, - help="""" - Require authentication to access prometheus metrics. - """, - config=True, - ) - - _starter_app = Instance( - default_value=None, - allow_none=True, - klass="jupyter_server.extension.application.ExtensionApp", - ) - - @property - def starter_app(self): - """Get the Extension that started this server.""" - return self._starter_app - - def parse_command_line(self, argv=None): - - super(ServerApp, self).parse_command_line(argv) - - if self.extra_args: - arg0 = self.extra_args[0] - f = os.path.abspath(arg0) - self.argv.remove(arg0) - if not os.path.exists(f): - self.log.critical(_i18n("No such file or directory: %s"), f) - self.exit(1) - - # Use config here, to ensure that it takes higher priority than - # anything that comes from the config dirs. - c = Config() - if os.path.isdir(f): - c.ServerApp.root_dir = f - elif os.path.isfile(f): - c.ServerApp.file_to_run = f - self.update_config(c) - - def init_configurables(self): - - # If gateway server is configured, replace appropriate managers to perform redirection. To make - # this determination, instantiate the GatewayClient config singleton. - self.gateway_config = GatewayClient.instance(parent=self) - - if self.gateway_config.gateway_enabled: - self.kernel_manager_class = ( - "jupyter_server.gateway.managers.GatewayMappingKernelManager" - ) - self.session_manager_class = "jupyter_server.gateway.managers.GatewaySessionManager" - self.kernel_spec_manager_class = ( - "jupyter_server.gateway.managers.GatewayKernelSpecManager" - ) - - self.kernel_spec_manager = self.kernel_spec_manager_class( - parent=self, - ) - self.kernel_manager = self.kernel_manager_class( - parent=self, - log=self.log, - connection_dir=self.runtime_dir, - kernel_spec_manager=self.kernel_spec_manager, - ) - self.contents_manager = self.contents_manager_class( - parent=self, - log=self.log, - ) - self.session_manager = self.session_manager_class( - parent=self, - log=self.log, - kernel_manager=self.kernel_manager, - contents_manager=self.contents_manager, - ) - self.config_manager = self.config_manager_class( - parent=self, - log=self.log, - ) - self.authorizer = self.authorizer_class(parent=self, log=self.log) - - def init_logging(self): - # This prevents double log messages because tornado use a root logger that - # self.log is a child of. The logging module dipatches log messages to a log - # and all of its ancenstors until propagate is set to False. - self.log.propagate = False - - for log in app_log, access_log, gen_log: - # consistent log output name (ServerApp instead of tornado.access, etc.) - log.name = self.log.name - # hook up tornado 3's loggers to our app handlers - logger = logging.getLogger("tornado") - logger.propagate = True - logger.parent = self.log - logger.setLevel(self.log.level) - - def init_webapp(self): - """initialize tornado webapp""" - self.tornado_settings["allow_origin"] = self.allow_origin - self.tornado_settings["websocket_compression_options"] = self.websocket_compression_options - if self.allow_origin_pat: - self.tornado_settings["allow_origin_pat"] = re.compile(self.allow_origin_pat) - self.tornado_settings["allow_credentials"] = self.allow_credentials - self.tornado_settings["autoreload"] = self.autoreload - self.tornado_settings["cookie_options"] = self.cookie_options - self.tornado_settings["get_secure_cookie_kwargs"] = self.get_secure_cookie_kwargs - self.tornado_settings["token"] = self.token - - # ensure default_url starts with base_url - if not self.default_url.startswith(self.base_url): - self.default_url = url_path_join(self.base_url, self.default_url) - - if self.password_required and (not self.password): - self.log.critical( - _i18n("Jupyter servers are configured to only be run with a password.") - ) - self.log.critical(_i18n("Hint: run the following command to set a password")) - self.log.critical(_i18n("\t$ python -m jupyter_server.auth password")) - sys.exit(1) - - # Socket options validation. - if self.sock: - if self.port != DEFAULT_JUPYTER_SERVER_PORT: - self.log.critical( - ("Options --port and --sock are mutually exclusive. Aborting."), - ) - sys.exit(1) - else: - # Reset the default port if we're using a UNIX socket. - self.port = 0 - - if self.open_browser: - # If we're bound to a UNIX socket, we can't reliably connect from a browser. - self.log.info( - ("Ignoring --ServerApp.open_browser due to --sock being used."), - ) - - if self.file_to_run: - self.log.critical( - ("Options --ServerApp.file_to_run and --sock are mutually exclusive."), - ) - sys.exit(1) - - if sys.platform.startswith("win"): - self.log.critical( - ( - "Option --sock is not supported on Windows, but got value of %s. Aborting." - % self.sock - ), - ) - sys.exit(1) - - self.web_app = ServerWebApplication( - self, - self.default_services, - self.kernel_manager, - self.contents_manager, - self.session_manager, - self.kernel_spec_manager, - self.config_manager, - self.extra_services, - self.log, - self.base_url, - self.default_url, - self.tornado_settings, - self.jinja_environment_options, - authorizer=self.authorizer, - ) - if self.certfile: - self.ssl_options["certfile"] = self.certfile - if self.keyfile: - self.ssl_options["keyfile"] = self.keyfile - if self.client_ca: - self.ssl_options["ca_certs"] = self.client_ca - if not self.ssl_options: - # could be an empty dict or None - # None indicates no SSL config - self.ssl_options = None - else: - # SSL may be missing, so only import it if it's to be used - import ssl - - # PROTOCOL_TLS selects the highest ssl/tls protocol version that both the client and - # server support. When PROTOCOL_TLS is not available use PROTOCOL_SSLv23. - self.ssl_options.setdefault( - "ssl_version", getattr(ssl, "PROTOCOL_TLS", ssl.PROTOCOL_SSLv23) - ) - if self.ssl_options.get("ca_certs", False): - self.ssl_options.setdefault("cert_reqs", ssl.CERT_REQUIRED) - ssl_options = self.ssl_options - - self.login_handler_class.validate_security(self, ssl_options=self.ssl_options) - - def init_resources(self): - """initialize system resources""" - if resource is None: - self.log.debug( - "Ignoring min_open_files_limit because the limit cannot be adjusted (for example, on Windows)" - ) - return - - old_soft, old_hard = resource.getrlimit(resource.RLIMIT_NOFILE) - soft = self.min_open_files_limit - hard = old_hard - if old_soft < soft: - if hard < soft: - hard = soft - self.log.debug( - "Raising open file limit: soft {}->{}; hard {}->{}".format( - old_soft, soft, old_hard, hard - ) - ) - resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard)) - - def _get_urlparts(self, path=None, include_token=False): - """Constructs a urllib named tuple, ParseResult, - with default values set by server config. - The returned tuple can be manipulated using the `_replace` method. - """ - if self.sock: - scheme = "http+unix" - netloc = urlencode_unix_socket_path(self.sock) - else: - # Handle nonexplicit hostname. - if self.ip in ("", "0.0.0.0", "::"): - ip = "%s" % socket.gethostname() - else: - ip = "[{}]".format(self.ip) if ":" in self.ip else self.ip - netloc = "{ip}:{port}".format(ip=ip, port=self.port) - if self.certfile: - scheme = "https" - else: - scheme = "http" - if not path: - path = self.default_url - query = None - if include_token: - if self.token: # Don't log full token if it came from config - token = self.token if self._token_generated else "..." - query = urllib.parse.urlencode({"token": token}) - # Build the URL Parts to dump. - urlparts = urllib.parse.ParseResult( - scheme=scheme, - netloc=netloc, - path=path, - params=None, - query=query, - fragment=None, - ) - return urlparts - - @property - def public_url(https://github.com/self): - parts = self._get_urlparts(include_token=True) - # Update with custom pieces. - if self.custom_display_url: - # Parse custom display_url - custom = urllib.parse.urlparse(self.custom_display_url)._asdict() - # Get pieces that are matter (non None) - custom_updates = {key: item for key, item in custom.items() if item} - # Update public URL parts with custom pieces. - parts = parts._replace(**custom_updates) - return parts.geturl() - - @property - def local_url(https://github.com/self): - parts = self._get_urlparts(include_token=True) - # Update with custom pieces. - if not self.sock: - parts = parts._replace(netloc="127.0.0.1:{port}".format(port=self.port)) - return parts.geturl() - - @property - def display_url(https://github.com/self): - """Human readable string with URLs for interacting - with the running Jupyter Server - """ - url = self.public_url + "\n or " + self.local_url - return url - - @property - def connection_url(https://github.com/self): - urlparts = self._get_urlparts(path=self.base_url) - return urlparts.geturl() - - def init_terminals(self): - if not self.terminals_enabled: - return - - try: - from jupyter_server.terminal import initialize - - initialize( - self.web_app, - self.root_dir, - self.connection_url, - self.terminado_settings, - ) - self.terminals_available = True - except ImportError as e: - self.log.warning(_i18n("Terminals not available (error was %s)"), e) - - def init_signal(self): - if not sys.platform.startswith("win") and sys.stdin and sys.stdin.isatty(): - signal.signal(signal.SIGINT, self._handle_sigint) - signal.signal(signal.SIGTERM, self._signal_stop) - if hasattr(signal, "SIGUSR1"): - # Windows doesn't support SIGUSR1 - signal.signal(signal.SIGUSR1, self._signal_info) - if hasattr(signal, "SIGINFO"): - # only on BSD-based systems - signal.signal(signal.SIGINFO, self._signal_info) - - def _handle_sigint(self, sig, frame): - """SIGINT handler spawns confirmation dialog""" - # register more forceful signal handler for ^C^C case - signal.signal(signal.SIGINT, self._signal_stop) - # request confirmation dialog in bg thread, to avoid - # blocking the App - thread = threading.Thread(target=self._confirm_exit) - thread.daemon = True - thread.start() - - def _restore_sigint_handler(self): - """callback for restoring original SIGINT handler""" - signal.signal(signal.SIGINT, self._handle_sigint) - - def _confirm_exit(self): - """confirm shutdown on ^C - - A second ^C, or answering 'y' within 5s will cause shutdown, - otherwise original SIGINT handler will be restored. - - This doesn't work on Windows. - """ - info = self.log.info - info(_i18n("interrupted")) - # Check if answer_yes is set - if self.answer_yes: - self.log.critical(_i18n("Shutting down...")) - # schedule stop on the main thread, - # since this might be called from a signal handler - self.stop(from_signal=True) - return - print(self.running_server_info()) - yes = _i18n("y") - no = _i18n("n") - sys.stdout.write(_i18n("Shutdown this Jupyter server (%s/[%s])? ") % (yes, no)) - sys.stdout.flush() - r, w, x = select.select([sys.stdin], [], [], 5) - if r: - line = sys.stdin.readline() - if line.lower().startswith(yes) and no not in line.lower(): - self.log.critical(_i18n("Shutdown confirmed")) - # schedule stop on the main thread, - # since this might be called from a signal handler - self.stop(from_signal=True) - return - else: - print(_i18n("No answer for 5s:"), end=" ") - print(_i18n("resuming operation...")) - # no answer, or answer is no: - # set it back to original SIGINT handler - # use IOLoop.add_callback because signal.signal must be called - # from main thread - self.io_loop.add_callback_from_signal(self._restore_sigint_handler) - - def _signal_stop(self, sig, frame): - self.log.critical(_i18n("received signal %s, stopping"), sig) - self.stop(from_signal=True) - - def _signal_info(self, sig, frame): - print(self.running_server_info()) - - def init_components(self): - """Check the components submodule, and warn if it's unclean""" - # TODO: this should still check, but now we use bower, not git submodule - pass - - def find_server_extensions(self): - """ - Searches Jupyter paths for jpserver_extensions. - """ - - # Walk through all config files looking for jpserver_extensions. - # - # Each extension will likely have a JSON config file enabling itself in - # the "jupyter_server_config.d" directory. Find each of these and - # merge there results in order of precedence. - # - # Load server extensions with ConfigManager. - # This enables merging on keys, which we want for extension enabling. - # Regular config loading only merges at the class level, - # so each level clobbers the previous. - config_paths = jupyter_config_path() - if self.config_dir not in config_paths: - # add self.config_dir to the front, if set manually - config_paths.insert(0, self.config_dir) - manager = ExtensionConfigManager(read_config_path=config_paths) - extensions = manager.get_jpserver_extensions() - - for modulename, enabled in sorted(extensions.items()): - if modulename not in self.jpserver_extensions: - self.config.ServerApp.jpserver_extensions.update({modulename: enabled}) - self.jpserver_extensions.update({modulename: enabled}) - - def init_server_extensions(self): - """ - If an extension's metadata includes an 'app' key, - the value must be a subclass of ExtensionApp. An instance - of the class will be created at this step. The config for - this instance will inherit the ServerApp's config object - and load its own config. - """ - # Create an instance of the ExtensionManager. - self.extension_manager = ExtensionManager(log=self.log, serverapp=self) - self.extension_manager.from_jpserver_extensions(self.jpserver_extensions) - self.extension_manager.link_all_extensions() - - def load_server_extensions(self): - """Load any extensions specified by config. - - Import the module, then call the load_jupyter_server_extension function, - if one exists. - - The extension API is experimental, and may change in future releases. - """ - self.extension_manager.load_all_extensions() - - def init_mime_overrides(self): - # On some Windows machines, an application has registered incorrect - # mimetypes in the registry. - # Tornado uses this when serving .css and .js files, causing browsers to - # reject these files. We know the mimetype always needs to be text/css for css - # and application/javascript for JS, so we override it here - # and explicitly tell the mimetypes to not trust the Windows registry - if os.name == "nt": - # do not trust windows registry, which regularly has bad info - mimetypes.init(files=[]) - # ensure css, js are correct, which are required for pages to function - mimetypes.add_type("text/css", ".css") - mimetypes.add_type("application/javascript", ".js") - # for python <3.8 - mimetypes.add_type("application/wasm", ".wasm") - - def shutdown_no_activity(self): - """Shutdown server on timeout when there are no kernels or terminals.""" - km = self.kernel_manager - if len(km) != 0: - return # Kernels still running - - if self.terminals_available: - term_mgr = self.web_app.settings["terminal_manager"] - if term_mgr.terminals: - return # Terminals still running - - seconds_since_active = (utcnow() - self.web_app.last_activity()).total_seconds() - self.log.debug("No activity for %d seconds.", seconds_since_active) - if seconds_since_active > self.shutdown_no_activity_timeout: - self.log.info( - "No kernels or terminals for %d seconds; shutting down.", - seconds_since_active, - ) - self.stop() - - def init_shutdown_no_activity(self): - if self.shutdown_no_activity_timeout > 0: - self.log.info( - "Will shut down after %d seconds with no kernels or terminals.", - self.shutdown_no_activity_timeout, - ) - pc = ioloop.PeriodicCallback(self.shutdown_no_activity, 60000) - pc.start() - - @property - def http_server(self): - """An instance of Tornado's HTTPServer class for the Server Web Application.""" - try: - return self._http_server - except AttributeError as e: - raise AttributeError( - "An HTTPServer instance has not been created for the " - "Server Web Application. To create an HTTPServer for this " - "application, call `.init_httpserver()`." - ) from e - - def init_httpserver(self): - """Creates an instance of a Tornado HTTPServer for the Server Web Application - and sets the http_server attribute. - """ - # Check that a web_app has been initialized before starting a server. - if not hasattr(self, "web_app"): - raise AttributeError( - "A tornado web application has not be initialized. " - "Try calling `.init_webapp()` first." - ) - - # Create an instance of the server. - self._http_server = httpserver.HTTPServer( - self.web_app, - ssl_options=self.ssl_options, - xheaders=self.trust_xheaders, - max_body_size=self.max_body_size, - max_buffer_size=self.max_buffer_size, - ) - - success = self._bind_http_server() - if not success: - self.log.critical( - _i18n( - "ERROR: the Jupyter server could not be started because " - "no available port could be found." - ) - ) - self.exit(1) - - def _bind_http_server(self): - return self._bind_http_server_unix() if self.sock else self._bind_http_server_tcp() - - def _bind_http_server_unix(self): - if unix_socket_in_use(self.sock): - self.log.warning(_i18n("The socket %s is already in use.") % self.sock) - return False - - try: - sock = bind_unix_socket(self.sock, mode=int(self.sock_mode.encode(), 8)) - self.http_server.add_socket(sock) - except socket.error as e: - if e.errno == errno.EADDRINUSE: - self.log.warning(_i18n("The socket %s is already in use.") % self.sock) - return False - elif e.errno in (errno.EACCES, getattr(errno, "WSAEACCES", errno.EACCES)): - self.log.warning(_i18n("Permission to listen on sock %s denied") % self.sock) - return False - else: - raise - else: - return True - - def _bind_http_server_tcp(self): - success = None - for port in random_ports(self.port, self.port_retries + 1): - try: - self.http_server.listen(port, self.ip) - except socket.error as e: - if e.errno == errno.EADDRINUSE: - if self.port_retries: - self.log.info( - _i18n("The port %i is already in use, trying another port.") % port - ) - else: - self.log.info(_i18n("The port %i is already in use.") % port) - continue - elif e.errno in ( - errno.EACCES, - getattr(errno, "WSAEACCES", errno.EACCES), - ): - self.log.warning(_i18n("Permission to listen on port %i denied.") % port) - continue - else: - raise - else: - self.port = port - success = True - break - if not success: - if self.port_retries: - self.log.critical( - _i18n( - "ERROR: the Jupyter server could not be started because " - "no available port could be found." - ) - ) - else: - self.log.critical( - _i18n( - "ERROR: the Jupyter server could not be started because " - "port %i is not available." - ) - % port - ) - self.exit(1) - return success - - @staticmethod - def _init_asyncio_patch(): - """set default asyncio policy to be compatible with tornado - - Tornado 6.0 is not compatible with default asyncio - ProactorEventLoop, which lacks basic *_reader methods. - Tornado 6.1 adds a workaround to add these methods in a thread, - but SelectorEventLoop should still be preferred - to avoid the extra thread for ~all of our events, - at least until asyncio adds *_reader methods - to proactor. - """ - if sys.platform.startswith("win") and sys.version_info >= (3, 8): - import asyncio - - try: - from asyncio import ( - WindowsProactorEventLoopPolicy, - WindowsSelectorEventLoopPolicy, - ) - except ImportError: - pass - # not affected - else: - if type(asyncio.get_event_loop_policy()) is WindowsProactorEventLoopPolicy: - # prefer Selector to Proactor for tornado + pyzmq - asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy()) - - @catch_config_error - def initialize( - self, - argv=None, - find_extensions=True, - new_httpserver=True, - starter_extension=None, - ): - """Initialize the Server application class, configurables, web application, and http server. - - Parameters - ---------- - argv : list or None - CLI arguments to parse. - find_extensions : bool - If True, find and load extensions listed in Jupyter config paths. If False, - only load extensions that are passed to ServerApp directy through - the `argv`, `config`, or `jpserver_extensions` arguments. - new_httpserver : bool - If True, a tornado HTTPServer instance will be created and configured for the Server Web - Application. This will set the http_server attribute of this class. - starter_extension : str - If given, it references the name of an extension point that started the Server. - We will try to load configuration from extension point - """ - self._init_asyncio_patch() - # Parse command line, load ServerApp config files, - # and update ServerApp config. - super(ServerApp, self).initialize(argv=argv) - if self._dispatching: - return - # Then, use extensions' config loading mechanism to - # update config. ServerApp config takes precedence. - if find_extensions: - self.find_server_extensions() - self.init_logging() - self.init_server_extensions() - - # Special case the starter extension and load - # any server configuration is provides. - if starter_extension: - # Configure ServerApp based on named extension. - point = self.extension_manager.extension_points[starter_extension] - # Set starter_app property. - if point.app: - self._starter_app = point.app - # Load any configuration that comes from the Extension point. - self.update_config(Config(point.config)) - - # Initialize other pieces of the server. - self.init_resources() - self.init_configurables() - self.init_components() - self.init_webapp() - self.init_terminals() - self.init_signal() - self.init_ioloop() - self.load_server_extensions() - self.init_mime_overrides() - self.init_shutdown_no_activity() - if new_httpserver: - self.init_httpserver() - - async def cleanup_kernels(self): - """Shutdown all kernels. - - The kernels will shutdown themselves when this process no longer exists, - but explicit shutdown allows the KernelManagers to cleanup the connection files. - """ - n_kernels = len(self.kernel_manager.list_kernel_ids()) - kernel_msg = trans.ngettext( - "Shutting down %d kernel", "Shutting down %d kernels", n_kernels - ) - self.log.info(kernel_msg % n_kernels) - await run_sync_in_loop(self.kernel_manager.shutdown_all()) - - async def cleanup_terminals(self): - """Shutdown all terminals. - - The terminals will shutdown themselves when this process no longer exists, - but explicit shutdown allows the TerminalManager to cleanup. - """ - if not self.terminals_available: - return - - terminal_manager = self.web_app.settings["terminal_manager"] - n_terminals = len(terminal_manager.list()) - terminal_msg = trans.ngettext( - "Shutting down %d terminal", "Shutting down %d terminals", n_terminals - ) - self.log.info(terminal_msg % n_terminals) - await run_sync_in_loop(terminal_manager.terminate_all()) - - async def cleanup_extensions(self): - """Call shutdown hooks in all extensions.""" - n_extensions = len(self.extension_manager.extension_apps) - extension_msg = trans.ngettext( - "Shutting down %d extension", "Shutting down %d extensions", n_extensions - ) - self.log.info(extension_msg % n_extensions) - await run_sync_in_loop(self.extension_manager.stop_all_extensions()) - - def running_server_info(self, kernel_count=True): - "Return the current working directory and the server url information" - info = self.contents_manager.info_string() + "\n" - if kernel_count: - n_kernels = len(self.kernel_manager.list_kernel_ids()) - kernel_msg = trans.ngettext("%d active kernel", "%d active kernels", n_kernels) - info += kernel_msg % n_kernels - info += "\n" - # Format the info so that the URL fits on a single line in 80 char display - info += _i18n( - "Jupyter Server {version} is running at:\n{url}".format( - version=ServerApp.version, url=self.display_url - ) - ) - if self.gateway_config.gateway_enabled: - info += ( - _i18n("\nKernels will be managed by the Gateway server running at:\n%s") - % self.gateway_config.url - ) - return info - - def server_info(self): - """Return a JSONable dict of information about this server.""" - return { - "url": self.connection_url, - "hostname": self.ip if self.ip else "localhost", - "port": self.port, - "sock": self.sock, - "secure": bool(self.certfile), - "base_url": self.base_url, - "token": self.token, - "root_dir": os.path.abspath(self.root_dir), - "password": bool(self.password), - "pid": os.getpid(), - "version": ServerApp.version, - } - - def write_server_info_file(self): - """Write the result of server_info() to the JSON file info_file.""" - try: - with secure_write(self.info_file) as f: - json.dump(self.server_info(), f, indent=2, sort_keys=True) - except OSError as e: - self.log.error(_i18n("Failed to write server-info to %s: %s"), self.info_file, e) - - def remove_server_info_file(self): - """Remove the jpserver-.json file created for this server. - - Ignores the error raised when the file has already been removed. - """ - try: - os.unlink(self.info_file) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def _resolve_file_to_run_and_root_dir(self): - """Returns a relative path from file_to_run - to root_dir. If root_dir and file_to_run - are incompatible, i.e. on different subtrees, - crash the app and log a critical message. Note - that if root_dir is not configured and file_to_run - is configured, root_dir will be set to the parent - directory of file_to_run. - """ - rootdir_abspath = pathlib.Path(self.root_dir).resolve() - file_rawpath = pathlib.Path(self.file_to_run) - combined_path = (rootdir_abspath / file_rawpath).resolve() - is_child = str(combined_path).startswith(str(rootdir_abspath)) - - if is_child: - if combined_path.parent != rootdir_abspath: - self.log.debug( - "The `root_dir` trait is set to a directory that's not " - "the immediate parent directory of `file_to_run`. Note that " - "the server will start at `root_dir` and open the " - "the file from the relative path to the `root_dir`." - ) - return str(combined_path.relative_to(rootdir_abspath)) - - self.log.critical( - "`root_dir` and `file_to_run` are incompatible. They " - "don't share the same subtrees. Make sure `file_to_run` " - "is on the same path as `root_dir`." - ) - self.exit(1) - - def _write_browser_open_file(self, url, fh): - if self.token: - url = url_concat(url, {"token": self.token}) - url = url_path_join(self.connection_url, url) - - jinja2_env = self.web_app.settings["jinja2_env"] - template = jinja2_env.get_template("browser-open.html") - fh.write(template.render(open_url=url, base_url=self.base_url)) - - def write_browser_open_files(self): - """Write an `browser_open_file` and `browser_open_file_to_run` files - - This can be used to open a file directly in a browser. - """ - # default_url contains base_url, but so does connection_url - self.write_browser_open_file() - - # Create a second browser open file if - # file_to_run is set. - if self.file_to_run: - # Make sure file_to_run and root_dir are compatible. - file_to_run_relpath = self._resolve_file_to_run_and_root_dir() - - file_open_url = url_escape( - url_path_join(self.file_url_prefix, *file_to_run_relpath.split(os.sep)) - ) - - with open(self.browser_open_file_to_run, "w", encoding="utf-8") as f: - self._write_browser_open_file(file_open_url, f) - - def write_browser_open_file(self): - """Write an jpserver--open.html file - - This can be used to open the notebook in a browser - """ - # default_url contains base_url, but so does connection_url - open_url = self.default_url[len(self.base_url) :] - - with open(self.browser_open_file, "w", encoding="utf-8") as f: - self._write_browser_open_file(open_url, f) - - def remove_browser_open_files(self): - """Remove the `browser_open_file` and `browser_open_file_to_run` files - created for this server. - - Ignores the error raised when the file has already been removed. - """ - self.remove_browser_open_file() - try: - os.unlink(self.browser_open_file_to_run) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def remove_browser_open_file(self): - """Remove the jpserver--open.html file created for this server. - - Ignores the error raised when the file has already been removed. - """ - try: - os.unlink(self.browser_open_file) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def _prepare_browser_open(self): - if not self.use_redirect_file: - uri = self.default_url[len(self.base_url) :] - - if self.token: - uri = url_concat(uri, {"token": self.token}) - - if self.file_to_run: - # Create a separate, temporary open-browser-file - # pointing at a specific file. - open_file = self.browser_open_file_to_run - else: - # otherwise, just return the usual open browser file. - open_file = self.browser_open_file - - if self.use_redirect_file: - assembled_url = urljoin("file:", pathname2url(https://github.com/open_file)) - else: - assembled_url = url_path_join(self.connection_url, uri) - - return assembled_url, open_file - - def launch_browser(self): - try: - browser = webbrowser.get(self.browser or None) - except webbrowser.Error as e: - self.log.warning(_i18n("No web browser found: %s.") % e) - browser = None - - if not browser: - return - - assembled_url, _ = self._prepare_browser_open() - - b = lambda: browser.open(assembled_url, new=self.webbrowser_open_new) - threading.Thread(target=b).start() - - def start_app(self): - super(ServerApp, self).start() - - if not self.allow_root: - # check if we are running as root, and abort if it's not allowed - try: - uid = os.geteuid() - except AttributeError: - uid = -1 # anything nonzero here, since we can't check UID assume non-root - if uid == 0: - self.log.critical( - _i18n("Running as root is not recommended. Use --allow-root to bypass.") - ) - self.exit(1) - - info = self.log.info - for line in self.running_server_info(kernel_count=False).split("\n"): - info(line) - info( - _i18n( - "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." - ) - ) - if "dev" in __version__: - info( - _i18n( - "Welcome to Project Kennen! Explore the various tools available" - " and their corresponding documentation. If you are interested" - " in contributing to the platform, please visit the community" - " resources section at https://jupyter.org/community.html." - ) - ) - - self.write_server_info_file() - self.write_browser_open_files() - - # Handle the browser opening. - if self.open_browser and not self.sock: - self.launch_browser() - - if self.token and self._token_generated: - # log full URL with generated token, so there's a copy/pasteable link - # with auth info. - if self.sock: - self.log.critical( - "\n".join( - [ - "\n", - "Kennen Server is listening on %s" % self.display_url, - "", - ( - "UNIX sockets are not browser-connectable, but you can tunnel to " - "the instance via e.g.`ssh -L 8888:%s -N user@this_host` and then " - "open e.g. %s in a browser." - ) - % (self.sock, self.connection_url), - ] - ) - ) - else: - self.log.critical( - "\n".join( - [ - "\n", - "To access the server, open this file in a browser:", - " %s" % urljoin("file:", pathname2url(https://github.com/self.browser_open_file)), - "Or copy and paste one of these URLs:", - " %s" % self.display_url, - ] - ) - ) - - async def _cleanup(self): - """General cleanup of files, extensions and kernels created - by this instance ServerApp. - """ - self.remove_server_info_file() - self.remove_browser_open_files() - await self.cleanup_extensions() - await self.cleanup_kernels() - await self.cleanup_terminals() - - def start_ioloop(self): - """Start the IO Loop.""" - if sys.platform.startswith("win"): - # add no-op to wake every 5s - # to handle signals that may be ignored by the inner loop - pc = ioloop.PeriodicCallback(lambda: None, 5000) - pc.start() - try: - self.io_loop.start() - except KeyboardInterrupt: - self.log.info(_i18n("Interrupted...")) - - def init_ioloop(self): - """init self.io_loop so that an extension can use it by io_loop.call_later() to create background tasks""" - self.io_loop = ioloop.IOLoop.current() - - def start(self): - """Start the Jupyter server app, after initialization - - This method takes no arguments so all configuration and initialization - must be done prior to calling this method.""" - self.start_app() - self.start_ioloop() - - async def _stop(self): - """Cleanup resources and stop the IO Loop.""" - await self._cleanup() - self.io_loop.stop() - - def stop(self, from_signal=False): - """Cleanup resources and stop the server.""" - if hasattr(self, "_http_server"): - # Stop a server if its set. - self.http_server.stop() - if getattr(self, "io_loop", None): - # use IOLoop.add_callback because signal.signal must be called - # from main thread - if from_signal: - self.io_loop.add_callback_from_signal(self._stop) - else: - self.io_loop.add_callback(self._stop) - - -def list_running_servers(runtime_dir=None, log=None): - """Iterate over the server info files of running Jupyter servers. - - Given a runtime directory, find jpserver-* files in the security directory, - and yield dicts of their information, each one pertaining to - a currently running Jupyter server instance. - """ - if runtime_dir is None: - runtime_dir = jupyter_runtime_dir() - - # The runtime dir might not exist - if not os.path.isdir(runtime_dir): - return - - for file_name in os.listdir(runtime_dir): - if re.match("jpserver-(.+).json", file_name): - with io.open(os.path.join(runtime_dir, file_name), encoding="utf-8") as f: - info = json.load(f) - - # Simple check whether that process is really still running - # Also remove leftover files from IPython 2.x without a pid field - if ("pid" in info) and check_pid(info["pid"]): - yield info - else: - # If the process has died, try to delete its info file - try: - os.unlink(os.path.join(runtime_dir, file_name)) - except OSError as e: - if log: - log.warning(_i18n("Deleting server info file failed: %s.") % e) - - -# ----------------------------------------------------------------------------- -# Main entry point -# ----------------------------------------------------------------------------- - -main = launch_new_instance = ServerApp.launch_instance diff --git a/server/jupyter_server/services/__init__.py b/server/jupyter_server/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/api/__init__.py b/server/jupyter_server/services/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/api/api.yaml b/server/jupyter_server/services/api/api.yaml deleted file mode 100644 index 87e901a..0000000 --- a/server/jupyter_server/services/api/api.yaml +++ /dev/null @@ -1,857 +0,0 @@ -swagger: "2.0" -info: - title: Kennen Server API - description: Server API - version: "5" - contact: - name: Kennen Project - url: https://jupyter.org -# will be prefixed to all paths -basePath: / -produces: - - application/json -consumes: - - application/json -parameters: - kernel: - name: kernel_id - required: true - in: path - description: kernel uuid - type: string - format: uuid - session: - name: session - required: true - in: path - description: session uuid - type: string - format: uuid - path: - name: path - required: true - in: path - description: file path - type: string - checkpoint_id: - name: checkpoint_id - required: true - in: path - description: Checkpoint id for a file - type: string - section_name: - name: section_name - required: true - in: path - description: Name of config section - type: string - terminal_id: - name: terminal_id - required: true - in: path - description: ID of terminal session - type: string - -paths: - /api/contents/{path}: - parameters: - - $ref: "#/parameters/path" - get: - summary: Get contents of file or directory - description: "A client can optionally specify a type and/or format argument via URL parameter. When given, the Contents service shall return a model in the requested type and/or format. If the request cannot be satisfied, e.g. type=text is requested, but the file is binary, then the request shall fail with 400 and have a JSON response containing a 'reason' field, with the value 'bad format' or 'bad type', depending on what was requested." - tags: - - contents - parameters: - - name: type - in: query - description: File type ('file', 'directory') - type: string - enum: - - file - - directory - - name: format - in: query - description: "How file content should be returned ('text', 'base64')" - type: string - enum: - - text - - base64 - - name: content - in: query - description: "Return content (0 for no content, 1 for return content)" - type: integer - responses: - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - 200: - description: Contents of file or directory - headers: - Last-Modified: - description: Last modified date for file - type: string - format: dateTime - schema: - $ref: "#/definitions/Contents" - 500: - description: Model key error - post: - summary: Create a new file in the specified path - description: "A POST to /api/contents/path creates a New untitled, empty file or directory. A POST to /api/contents/path with body {'copy_from': '/path/to/OtherNotebook.ipynb'} creates a new copy of OtherNotebook in path." - tags: - - contents - parameters: - - name: model - in: body - description: Path of file to copy - schema: - type: object - properties: - copy_from: - type: string - ext: - type: string - type: - type: string - responses: - 201: - description: File created - headers: - Location: - description: URL for the new file - type: string - format: url - schema: - $ref: "#/definitions/Contents" - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - patch: - summary: Rename a file or directory without re-uploading content - tags: - - contents - parameters: - - name: path - in: body - required: true - description: New path for file or directory. - schema: - type: object - properties: - path: - type: string - format: path - description: New path for file or directory - responses: - 200: - description: Path updated - headers: - Location: - description: Updated URL for the file or directory - type: string - format: url - schema: - $ref: "#/definitions/Contents" - 400: - description: No data provided - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - put: - summary: Save or upload file. - description: "Saves the file in the location specified by name and path. PUT is very similar to POST, but the requester specifies the name, whereas with POST, the server picks the name." - tags: - - contents - parameters: - - name: model - in: body - description: New path for file or directory - schema: - type: object - properties: - name: - type: string - description: The new filename if changed - path: - type: string - description: New path for file or directory - type: - type: string - description: Path dtype ('notebook', 'file', 'directory') - format: - type: string - description: File format ('json', 'text', 'base64') - content: - type: string - description: The actual body of the document excluding directory type - responses: - 200: - description: File saved - headers: - Location: - description: Updated URL for the file or directory - type: string - format: url - schema: - $ref: "#/definitions/Contents" - 201: - description: Path created - headers: - Location: - description: URL for the file or directory - type: string - format: url - schema: - $ref: "#/definitions/Contents" - 400: - description: No data provided - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - delete: - summary: Delete a file in the given path - tags: - - contents - responses: - 204: - description: File deleted - headers: - Location: - description: URL for the removed file - type: string - format: url - /api/contents/{path}/checkpoints: - parameters: - - $ref: "#/parameters/path" - get: - summary: Get a list of checkpoints for a file - description: List checkpoints for a given file. There will typically be zero or one results. - tags: - - contents - responses: - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - 200: - description: List of checkpoints for a file - schema: - type: array - items: - $ref: "#/definitions/Checkpoints" - 500: - description: Model key error - post: - summary: Create a new checkpoint for a file - description: "Create a new checkpoint with the current state of a file. With the default FileContentsManager, only one checkpoint is supported, so creating new checkpoints clobbers existing ones." - tags: - - contents - responses: - 201: - description: Checkpoint created - headers: - Location: - description: URL for the checkpoint - type: string - format: url - schema: - $ref: "#/definitions/Checkpoints" - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - /api/contents/{path}/checkpoints/{checkpoint_id}: - post: - summary: Restore a file to a particular checkpointed state - parameters: - - $ref: "#/parameters/path" - - $ref: "#/parameters/checkpoint_id" - tags: - - contents - responses: - 204: - description: Checkpoint restored - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - delete: - summary: Delete a checkpoint - parameters: - - $ref: "#/parameters/path" - - $ref: "#/parameters/checkpoint_id" - tags: - - contents - responses: - 204: - description: Checkpoint deleted - /api/sessions/{session}: - parameters: - - $ref: "#/parameters/session" - get: - summary: Get session - tags: - - sessions - responses: - 200: - description: Session - schema: - $ref: "#/definitions/Session" - patch: - summary: "This can be used to rename the session." - tags: - - sessions - parameters: - - name: model - in: body - required: true - schema: - $ref: "#/definitions/Session" - responses: - 200: - description: Session - schema: - $ref: "#/definitions/Session" - 400: - description: No data provided - delete: - summary: Delete a session - tags: - - sessions - responses: - 204: - description: Session (and kernel) were deleted - 410: - description: "Kernel was deleted before the session, and the session was *not* deleted (TODO - check to make sure session wasn't deleted)" - /api/sessions: - get: - summary: List available sessions - tags: - - sessions - responses: - 200: - description: List of current sessions - schema: - type: array - items: - $ref: "#/definitions/Session" - post: - summary: "Create a new session, or return an existing session if a session of the same name already exists" - tags: - - sessions - parameters: - - name: session - in: body - schema: - $ref: "#/definitions/Session" - responses: - 201: - description: Session created or returned - schema: - $ref: "#/definitions/Session" - headers: - Location: - description: URL for session commands - type: string - format: url - 501: - description: Session not available - schema: - type: object - description: error message - properties: - message: - type: string - short_message: - type: string - - /api/kernels: - get: - summary: List the JSON data for all kernels that are currently running - tags: - - kernels - responses: - 200: - description: List of currently-running kernel uuids - schema: - type: array - items: - $ref: "#/definitions/Kernel" - post: - summary: Start a kernel and return the uuid - tags: - - kernels - parameters: - - name: options - in: body - schema: - type: object - required: - - name - properties: - name: - type: string - description: Kernel spec name (defaults to default kernel spec for server) - path: - type: string - description: API path from root to the cwd of the kernel - responses: - 201: - description: Kernel started - schema: - $ref: "#/definitions/Kernel" - headers: - Location: - description: Model for started kernel - type: string - format: url - /api/kernels/{kernel_id}: - parameters: - - $ref: "#/parameters/kernel" - get: - summary: Get kernel information - tags: - - kernels - responses: - 200: - description: Kernel information - schema: - $ref: "#/definitions/Kernel" - delete: - summary: Kill a kernel and delete the kernel id - tags: - - kernels - responses: - 204: - description: Kernel deleted - /api/kernels/{kernel_id}/interrupt: - parameters: - - $ref: "#/parameters/kernel" - post: - summary: Interrupt a kernel - tags: - - kernels - responses: - 204: - description: Kernel interrupted - /api/kernels/{kernel_id}/restart: - parameters: - - $ref: "#/parameters/kernel" - post: - summary: Restart a kernel - tags: - - kernels - responses: - 200: - description: Kernel restarted - headers: - Location: - description: URL for kernel commands - type: string - format: url - schema: - $ref: "#/definitions/Kernel" - - /api/kernelspecs: - get: - summary: Get kernel specs - tags: - - kernelspecs - responses: - 200: - description: Kernel specs - schema: - type: object - properties: - default: - type: string - description: Default kernel name - kernelspecs: - type: object - additionalProperties: - $ref: "#/definitions/KernelSpec" - /api/config/{section_name}: - get: - summary: Get a configuration section by name - parameters: - - $ref: "#/parameters/section_name" - tags: - - config - responses: - 200: - description: Configuration object - schema: - type: object - patch: - summary: Update a configuration section by name - tags: - - config - parameters: - - $ref: "#/parameters/section_name" - - name: configuration - in: body - schema: - type: object - responses: - 200: - description: Configuration object - schema: - type: object - - /api/terminals: - get: - summary: Get available terminals - tags: - - terminals - responses: - 200: - description: A list of all available terminal ids. - schema: - type: array - items: - $ref: "#/definitions/Terminal" - 403: - description: Forbidden to access - 404: - description: Not found - - post: - summary: Create a new terminal - tags: - - terminals - responses: - 200: - description: Succesfully created a new terminal - schema: - $ref: "#/definitions/Terminal" - 403: - description: Forbidden to access - 404: - description: Not found - - /api/terminals/{terminal_id}: - get: - summary: Get a terminal session corresponding to an id. - tags: - - terminals - parameters: - - $ref: "#/parameters/terminal_id" - responses: - 200: - description: Terminal session with given id - schema: - $ref: "#/definitions/Terminal" - 403: - description: Forbidden to access - 404: - description: Not found - - delete: - summary: Delete a terminal session corresponding to an id. - tags: - - terminals - parameters: - - $ref: "#/parameters/terminal_id" - responses: - 204: - description: Succesfully deleted terminal session - 403: - description: Forbidden to access - 404: - description: Not found - - /api/status: - get: - summary: Get the current status/activity of the server. - tags: - - status - responses: - 200: - description: The current status of the server - schema: - $ref: "#/definitions/APIStatus" - - /api/spec.yaml: - get: - summary: Get the current spec for the notebook server's APIs. - tags: - - api-spec - produces: - - text/x-yaml - responses: - 200: - description: The current spec for the notebook server's APIs. - schema: - type: file -definitions: - APIStatus: - description: | - Notebook server API status. - Added in notebook 5.0. - properties: - started: - type: string - description: | - ISO8601 timestamp indicating when the notebook server started. - last_activity: - type: string - description: | - ISO8601 timestamp indicating the last activity on the server, - either on the REST API or kernel activity. - connections: - type: number - description: | - The total number of currently open connections to kernels. - kernels: - type: number - description: | - The total number of running kernels. - KernelSpec: - description: Kernel spec (contents of kernel.json) - properties: - name: - type: string - description: Unique name for kernel - KernelSpecFile: - $ref: "#/definitions/KernelSpecFile" - resources: - type: object - properties: - kernel.js: - type: string - format: filename - description: path for kernel.js file - kernel.css: - type: string - format: filename - description: path for kernel.css file - logo-*: - type: string - format: filename - description: path for logo file. Logo filenames are of the form `logo-widthxheight` - KernelSpecFile: - description: Kernel spec json file - required: - - argv - - display_name - - language - properties: - language: - type: string - description: The programming language which this kernel runs. This will be stored in notebook metadata. - argv: - type: array - description: "A list of command line arguments used to start the kernel. The text `{connection_file}` in any argument will be replaced with the path to the connection file." - items: - type: string - display_name: - type: string - description: "The kernel's name as it should be displayed in the UI. Unlike the kernel name used in the API, this can contain arbitrary unicode characters." - codemirror_mode: - type: string - description: Codemirror mode. Can be a string *or* an valid Codemirror mode object. This defaults to the string from the `language` property. - env: - type: object - description: A dictionary of environment variables to set for the kernel. These will be added to the current environment variables. - additionalProperties: - type: string - help_links: - type: array - description: Help items to be displayed in the help menu in the notebook UI. - items: - type: object - required: - - text - - url - properties: - text: - type: string - description: menu item link text - url: - type: string - format: URL - description: menu item link url - Kernel: - description: Kernel information - required: - - id - - name - properties: - id: - type: string - format: uuid - description: uuid of kernel - name: - type: string - description: kernel spec name - last_activity: - type: string - description: | - ISO 8601 timestamp for the last-seen activity on this kernel. - Use this in combination with execution_state == 'idle' to identify - which kernels have been idle since a given time. - Timestamps will be UTC, indicated 'Z' suffix. - Added in notebook server 5.0. - connections: - type: number - description: | - The number of active connections to this kernel. - execution_state: - type: string - description: | - Current execution state of the kernel (typically 'idle' or 'busy', but may be other values, such as 'starting'). - Added in notebook server 5.0. - Session: - description: A session - type: object - properties: - id: - type: string - format: uuid - path: - type: string - description: path to the session - name: - type: string - description: name of the session - type: - type: string - description: session type - kernel: - $ref: "#/definitions/Kernel" - Contents: - description: "A contents object. The content and format keys may be null if content is not contained. If type is 'file', then the mimetype will be null." - type: object - required: - - type - - name - - path - - writable - - created - - last_modified - - mimetype - - format - - content - properties: - name: - type: string - description: "Name of file or directory, equivalent to the last part of the path" - path: - type: string - description: Full path for file or directory - type: - type: string - description: Type of content - enum: - - directory - - file - - notebook - writable: - type: boolean - description: indicates whether the requester has permission to edit the file - created: - type: string - description: Creation timestamp - format: dateTime - last_modified: - type: string - description: Last modified timestamp - format: dateTime - size: - type: integer - description: "The size of the file or notebook in bytes. If no size is provided, defaults to null." - mimetype: - type: string - description: "The mimetype of a file. If content is not null, and type is 'file', this will contain the mimetype of the file, otherwise this will be null." - content: - type: string - description: "The content, if requested (otherwise null). Will be an array if type is 'directory'" - format: - type: string - description: Format of content (one of null, 'text', 'base64', 'json') - Checkpoints: - description: A checkpoint object. - type: object - required: - - id - - last_modified - properties: - id: - type: string - description: Unique id for the checkpoint. - last_modified: - type: string - description: Last modified timestamp - format: dateTime - Terminal: - description: A Terminal object - type: object - required: - - name - properties: - name: - type: string - description: name of terminal - last_activity: - type: string - description: | - ISO 8601 timestamp for the last-seen activity on this terminal. Use - this to identify which terminals have been inactive since a given time. - Timestamps will be UTC, indicated 'Z' suffix. diff --git a/server/jupyter_server/services/api/handlers.py b/server/jupyter_server/services/api/handlers.py deleted file mode 100644 index 8974215..0000000 --- a/server/jupyter_server/services/api/handlers.py +++ /dev/null @@ -1,63 +0,0 @@ -"""Tornado handlers for api specifications.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -import os - -from tornado import web - -from ...base.handlers import APIHandler -from ...base.handlers import JupyterHandler -from jupyter_server._tz import isoformat -from jupyter_server._tz import utcfromtimestamp -from jupyter_server.auth import authorized -from jupyter_server.utils import ensure_async - - -AUTH_RESOURCE = "api" - - -class APISpecHandler(web.StaticFileHandler, JupyterHandler): - auth_resource = AUTH_RESOURCE - - def initialize(self): - web.StaticFileHandler.initialize(self, path=os.path.dirname(__file__)) - - @web.authenticated - @authorized - def get(self): - self.log.warning("Serving api spec (experimental, incomplete)") - return web.StaticFileHandler.get(self, "api.yaml") - - def get_content_type(self): - return "text/x-yaml" - - -class APIStatusHandler(APIHandler): - - auth_resource = AUTH_RESOURCE - _track_activity = False - - @web.authenticated - @authorized - async def get(self): - # if started was missing, use unix epoch - started = self.settings.get("started", utcfromtimestamp(0)) - started = isoformat(started) - - kernels = await ensure_async(self.kernel_manager.list_kernels()) - total_connections = sum(k["connections"] for k in kernels) - last_activity = isoformat(self.application.last_activity()) - model = { - "started": started, - "last_activity": last_activity, - "kernels": len(kernels), - "connections": total_connections, - } - self.finish(json.dumps(model, sort_keys=True)) - - -default_handlers = [ - (r"/api/spec.yaml", APISpecHandler), - (r"/api/status", APIStatusHandler), -] diff --git a/server/jupyter_server/services/config/__init__.py b/server/jupyter_server/services/config/__init__.py deleted file mode 100644 index 9a2aee2..0000000 --- a/server/jupyter_server/services/config/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .manager import ConfigManager # noqa diff --git a/server/jupyter_server/services/config/handlers.py b/server/jupyter_server/services/config/handlers.py deleted file mode 100644 index 09bb88f..0000000 --- a/server/jupyter_server/services/config/handlers.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Tornado handlers for frontend config storage.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json - -from tornado import web - -from ...base.handlers import APIHandler -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "config" - - -class ConfigHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - @web.authenticated - @authorized - def get(self, section_name): - self.set_header("Content-Type", "application/json") - self.finish(json.dumps(self.config_manager.get(section_name))) - - @web.authenticated - @authorized - def put(self, section_name): - data = self.get_json_body() # Will raise 400 if content is not valid JSON - self.config_manager.set(section_name, data) - self.set_status(204) - - @web.authenticated - @authorized - def patch(self, section_name): - new_data = self.get_json_body() - section = self.config_manager.update(section_name, new_data) - self.finish(json.dumps(section)) - - -# URL to handler mappings - -section_name_regex = r"(?P\w+)" - -default_handlers = [ - (r"/api/config/%s" % section_name_regex, ConfigHandler), -] diff --git a/server/jupyter_server/services/config/manager.py b/server/jupyter_server/services/config/manager.py deleted file mode 100644 index b252cf5..0000000 --- a/server/jupyter_server/services/config/manager.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Manager to read and modify frontend config data in JSON files. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os.path - -from jupyter_core.paths import jupyter_config_dir -from jupyter_core.paths import jupyter_config_path -from traitlets import default -from traitlets import Instance -from traitlets import List -from traitlets import observe -from traitlets import Unicode -from traitlets.config import LoggingConfigurable - -from jupyter_server.config_manager import BaseJSONConfigManager -from jupyter_server.config_manager import recursive_update - - -class ConfigManager(LoggingConfigurable): - """Config Manager used for storing frontend config""" - - config_dir_name = Unicode("serverconfig", help="""Name of the config directory.""").tag( - config=True - ) - - # Public API - - def get(self, section_name): - """Get the config from all config sections.""" - config = {} - # step through back to front, to ensure front of the list is top priority - for p in self.read_config_path[::-1]: - cm = BaseJSONConfigManager(config_dir=p) - recursive_update(config, cm.get(section_name)) - return config - - def set(self, section_name, data): - """Set the config only to the user's config.""" - return self.write_config_manager.set(section_name, data) - - def update(self, section_name, new_data): - """Update the config only to the user's config.""" - return self.write_config_manager.update(section_name, new_data) - - # Private API - - read_config_path = List(Unicode()) - - @default("read_config_path") - def _default_read_config_path(self): - return [os.path.join(p, self.config_dir_name) for p in jupyter_config_path()] - - write_config_dir = Unicode() - - @default("write_config_dir") - def _default_write_config_dir(self): - return os.path.join(jupyter_config_dir(), self.config_dir_name) - - write_config_manager = Instance(BaseJSONConfigManager) - - @default("write_config_manager") - def _default_write_config_manager(self): - return BaseJSONConfigManager(config_dir=self.write_config_dir) - - @observe("write_config_dir") - def _update_write_config_dir(self, change): - self.write_config_manager = BaseJSONConfigManager(config_dir=self.write_config_dir) diff --git a/server/jupyter_server/services/contents/__init__.py b/server/jupyter_server/services/contents/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/contents/checkpoints.py b/server/jupyter_server/services/contents/checkpoints.py deleted file mode 100644 index 7a5fa2e..0000000 --- a/server/jupyter_server/services/contents/checkpoints.py +++ /dev/null @@ -1,249 +0,0 @@ -""" -Classes for managing Checkpoints. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from tornado.web import HTTPError -from traitlets.config.configurable import LoggingConfigurable - - -class Checkpoints(LoggingConfigurable): - """ - Base class for managing checkpoints for a ContentsManager. - - Subclasses are required to implement: - - create_checkpoint(self, contents_mgr, path) - restore_checkpoint(self, contents_mgr, checkpoint_id, path) - rename_checkpoint(self, checkpoint_id, old_path, new_path) - delete_checkpoint(self, checkpoint_id, path) - list_checkpoints(self, path) - """ - - def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - raise NotImplementedError("must be implemented in a subclass") - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint""" - raise NotImplementedError("must be implemented in a subclass") - - def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a single checkpoint from old_path to new_path.""" - raise NotImplementedError("must be implemented in a subclass") - - def delete_checkpoint(self, checkpoint_id, path): - """delete a checkpoint for a file""" - raise NotImplementedError("must be implemented in a subclass") - - def list_checkpoints(self, path): - """Return a list of checkpoints for a given file""" - raise NotImplementedError("must be implemented in a subclass") - - def rename_all_checkpoints(self, old_path, new_path): - """Rename all checkpoints for old_path to new_path.""" - for cp in self.list_checkpoints(old_path): - self.rename_checkpoint(cp["id"], old_path, new_path) - - def delete_all_checkpoints(self, path): - """Delete all checkpoints for the given path.""" - for checkpoint in self.list_checkpoints(path): - self.delete_checkpoint(checkpoint["id"], path) - - -class GenericCheckpointsMixin(object): - """ - Helper for creating Checkpoints subclasses that can be used with any - ContentsManager. - - Provides a ContentsManager-agnostic implementation of `create_checkpoint` - and `restore_checkpoint` in terms of the following operations: - - - create_file_checkpoint(self, content, format, path) - - create_notebook_checkpoint(self, nb, path) - - get_file_checkpoint(self, checkpoint_id, path) - - get_notebook_checkpoint(self, checkpoint_id, path) - - To create a generic CheckpointManager, add this mixin to a class that - implement the above four methods plus the remaining Checkpoints API - methods: - - - delete_checkpoint(self, checkpoint_id, path) - - list_checkpoints(self, path) - - rename_checkpoint(self, checkpoint_id, old_path, new_path) - """ - - def create_checkpoint(self, contents_mgr, path): - model = contents_mgr.get(path, content=True) - type = model["type"] - if type == "notebook": - return self.create_notebook_checkpoint( - model["content"], - path, - ) - elif type == "file": - return self.create_file_checkpoint( - model["content"], - model["format"], - path, - ) - else: - raise HTTPError(500, "Unexpected type %s" % type) - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - type = contents_mgr.get(path, content=False)["type"] - if type == "notebook": - model = self.get_notebook_checkpoint(checkpoint_id, path) - elif type == "file": - model = self.get_file_checkpoint(checkpoint_id, path) - else: - raise HTTPError(500, "Unexpected type %s" % type) - contents_mgr.save(model, path) - - # Required Methods - def create_file_checkpoint(self, content, format, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - def get_file_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a non-notebook file. - - Returns a dict of the form: - { - 'type': 'file', - 'content': , - 'format': {'text','base64'}, - } - """ - raise NotImplementedError("must be implemented in a subclass") - - def get_notebook_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a notebook. - - Returns a dict of the form: - { - 'type': 'notebook', - 'content': , - } - """ - raise NotImplementedError("must be implemented in a subclass") - - -class AsyncCheckpoints(Checkpoints): - """ - Base class for managing checkpoints for a ContentsManager asynchronously. - """ - - async def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - raise NotImplementedError("must be implemented in a subclass") - - async def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint""" - raise NotImplementedError("must be implemented in a subclass") - - async def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a single checkpoint from old_path to new_path.""" - raise NotImplementedError("must be implemented in a subclass") - - async def delete_checkpoint(self, checkpoint_id, path): - """delete a checkpoint for a file""" - raise NotImplementedError("must be implemented in a subclass") - - async def list_checkpoints(self, path): - """Return a list of checkpoints for a given file""" - raise NotImplementedError("must be implemented in a subclass") - - async def rename_all_checkpoints(self, old_path, new_path): - """Rename all checkpoints for old_path to new_path.""" - for cp in await self.list_checkpoints(old_path): - await self.rename_checkpoint(cp["id"], old_path, new_path) - - async def delete_all_checkpoints(self, path): - """Delete all checkpoints for the given path.""" - for checkpoint in await self.list_checkpoints(path): - await self.delete_checkpoint(checkpoint["id"], path) - - -class AsyncGenericCheckpointsMixin(GenericCheckpointsMixin): - """ - Helper for creating Asynchronous Checkpoints subclasses that can be used with any - ContentsManager. - """ - - async def create_checkpoint(self, contents_mgr, path): - model = await contents_mgr.get(path, content=True) - type = model["type"] - if type == "notebook": - return await self.create_notebook_checkpoint( - model["content"], - path, - ) - elif type == "file": - return await self.create_file_checkpoint( - model["content"], - model["format"], - path, - ) - else: - raise HTTPError(500, "Unexpected type %s" % type) - - async def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - type = await contents_mgr.get(path, content=False)["type"] - if type == "notebook": - model = await self.get_notebook_checkpoint(checkpoint_id, path) - elif type == "file": - model = await self.get_file_checkpoint(checkpoint_id, path) - else: - raise HTTPError(500, "Unexpected type %s" % type) - await contents_mgr.save(model, path) - - # Required Methods - async def create_file_checkpoint(self, content, format, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - async def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - async def get_file_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a non-notebook file. - - Returns a dict of the form: - { - 'type': 'file', - 'content': , - 'format': {'text','base64'}, - } - """ - raise NotImplementedError("must be implemented in a subclass") - - async def get_notebook_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a notebook. - - Returns a dict of the form: - { - 'type': 'notebook', - 'content': , - } - """ - raise NotImplementedError("must be implemented in a subclass") diff --git a/server/jupyter_server/services/contents/filecheckpoints.py b/server/jupyter_server/services/contents/filecheckpoints.py deleted file mode 100644 index b4c89f7..0000000 --- a/server/jupyter_server/services/contents/filecheckpoints.py +++ /dev/null @@ -1,329 +0,0 @@ -""" -File-based Checkpoints implementations. -""" -import os -import shutil - -from anyio.to_thread import run_sync -from jupyter_core.utils import ensure_dir_exists -from tornado.web import HTTPError -from traitlets import Unicode - -from .checkpoints import AsyncCheckpoints -from .checkpoints import AsyncGenericCheckpointsMixin -from .checkpoints import Checkpoints -from .checkpoints import GenericCheckpointsMixin -from .fileio import AsyncFileManagerMixin -from .fileio import FileManagerMixin -from jupyter_server import _tz as tz - - -class FileCheckpoints(FileManagerMixin, Checkpoints): - """ - A Checkpoints that caches checkpoints for files in adjacent - directories. - - Only works with FileContentsManager. Use GenericFileCheckpoints if - you want file-based checkpoints with another ContentsManager. - """ - - checkpoint_dir = Unicode( - ".ipynb_checkpoints", - config=True, - help="""The directory name in which to keep file checkpoints - - This is a path relative to the file's own directory. - - By default, it is .ipynb_checkpoints - """, - ) - - root_dir = Unicode(config=True) - - def _root_dir_default(self): - try: - return self.parent.root_dir - except AttributeError: - return os.getcwd() - - # ContentsManager-dependent checkpoint API - def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - checkpoint_id = "checkpoint" - src_path = contents_mgr._get_os_path(path) - dest_path = self.checkpoint_path(checkpoint_id, path) - self._copy(src_path, dest_path) - return self.checkpoint_model(checkpoint_id, dest_path) - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - src_path = self.checkpoint_path(checkpoint_id, path) - dest_path = contents_mgr._get_os_path(path) - self._copy(src_path, dest_path) - - # ContentsManager-independent checkpoint API - def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a checkpoint from old_path to new_path.""" - old_cp_path = self.checkpoint_path(checkpoint_id, old_path) - new_cp_path = self.checkpoint_path(checkpoint_id, new_path) - if os.path.isfile(old_cp_path): - self.log.debug( - "Renaming checkpoint %s -> %s", - old_cp_path, - new_cp_path, - ) - with self.perm_to_403(): - shutil.move(old_cp_path, new_cp_path) - - def delete_checkpoint(self, checkpoint_id, path): - """delete a file's checkpoint""" - path = path.strip("/") - cp_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(cp_path): - self.no_such_checkpoint(path, checkpoint_id) - - self.log.debug("unlinking %s", cp_path) - with self.perm_to_403(): - os.unlink(cp_path) - - def list_checkpoints(self, path): - """list the checkpoints for a given file - - This contents manager currently only supports one checkpoint per file. - """ - path = path.strip("/") - checkpoint_id = "checkpoint" - os_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(os_path): - return [] - else: - return [self.checkpoint_model(checkpoint_id, os_path)] - - # Checkpoint-related utilities - def checkpoint_path(self, checkpoint_id, path): - """find the path to a checkpoint""" - path = path.strip("/") - parent, name = ("/" + path).rsplit("/", 1) - parent = parent.strip("/") - basename, ext = os.path.splitext(name) - filename = "{name}-{checkpoint_id}{ext}".format( - name=basename, - checkpoint_id=checkpoint_id, - ext=ext, - ) - os_path = self._get_os_path(path=parent) - cp_dir = os.path.join(os_path, self.checkpoint_dir) - with self.perm_to_403(): - ensure_dir_exists(cp_dir) - cp_path = os.path.join(cp_dir, filename) - return cp_path - - def checkpoint_model(self, checkpoint_id, os_path): - """construct the info dict for a given checkpoint""" - stats = os.stat(os_path) - last_modified = tz.utcfromtimestamp(stats.st_mtime) - info = dict( - id=checkpoint_id, - last_modified=last_modified, - ) - return info - - # Error Handling - def no_such_checkpoint(self, path, checkpoint_id): - raise HTTPError(404, "Checkpoint does not exist: %s@%s" % (path, checkpoint_id)) - - -class AsyncFileCheckpoints(FileCheckpoints, AsyncFileManagerMixin, AsyncCheckpoints): - async def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - checkpoint_id = "checkpoint" - src_path = contents_mgr._get_os_path(path) - dest_path = self.checkpoint_path(checkpoint_id, path) - await self._copy(src_path, dest_path) - return await self.checkpoint_model(checkpoint_id, dest_path) - - async def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - src_path = self.checkpoint_path(checkpoint_id, path) - dest_path = contents_mgr._get_os_path(path) - await self._copy(src_path, dest_path) - - async def checkpoint_model(self, checkpoint_id, os_path): - """construct the info dict for a given checkpoint""" - stats = await run_sync(os.stat, os_path) - last_modified = tz.utcfromtimestamp(stats.st_mtime) - info = dict( - id=checkpoint_id, - last_modified=last_modified, - ) - return info - - # ContentsManager-independent checkpoint API - async def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a checkpoint from old_path to new_path.""" - old_cp_path = self.checkpoint_path(checkpoint_id, old_path) - new_cp_path = self.checkpoint_path(checkpoint_id, new_path) - if os.path.isfile(old_cp_path): - self.log.debug( - "Renaming checkpoint %s -> %s", - old_cp_path, - new_cp_path, - ) - with self.perm_to_403(): - await run_sync(shutil.move, old_cp_path, new_cp_path) - - async def delete_checkpoint(self, checkpoint_id, path): - """delete a file's checkpoint""" - path = path.strip("/") - cp_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(cp_path): - self.no_such_checkpoint(path, checkpoint_id) - - self.log.debug("unlinking %s", cp_path) - with self.perm_to_403(): - await run_sync(os.unlink, cp_path) - - async def list_checkpoints(self, path): - """list the checkpoints for a given file - - This contents manager currently only supports one checkpoint per file. - """ - path = path.strip("/") - checkpoint_id = "checkpoint" - os_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(os_path): - return [] - else: - return [await self.checkpoint_model(checkpoint_id, os_path)] - - -class GenericFileCheckpoints(GenericCheckpointsMixin, FileCheckpoints): - """ - Local filesystem Checkpoints that works with any conforming - ContentsManager. - """ - - def create_file_checkpoint(self, content, format, path): - """Create a checkpoint from the current content of a file.""" - path = path.strip("/") - # only the one checkpoint ID: - checkpoint_id = "checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - self._save_file(os_checkpoint_path, content, format=format) - - # return the checkpoint info - return self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint from the current content of a notebook.""" - path = path.strip("/") - # only the one checkpoint ID: - checkpoint_id = "checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - self._save_notebook(os_checkpoint_path, nb) - - # return the checkpoint info - return self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - def get_notebook_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a notebook.""" - path = path.strip("/") - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - return { - "type": "notebook", - "content": self._read_notebook( - os_checkpoint_path, - as_version=4, - ), - } - - def get_file_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a file.""" - path = path.strip("/") - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - content, format = self._read_file(os_checkpoint_path, format=None) - return { - "type": "file", - "content": content, - "format": format, - } - - -class AsyncGenericFileCheckpoints(AsyncGenericCheckpointsMixin, AsyncFileCheckpoints): - """ - Asynchronous Local filesystem Checkpoints that works with any conforming - ContentsManager. - """ - - async def create_file_checkpoint(self, content, format, path): - """Create a checkpoint from the current content of a file.""" - path = path.strip("/") - # only the one checkpoint ID: - checkpoint_id = "checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - await self._save_file(os_checkpoint_path, content, format=format) - - # return the checkpoint info - return await self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - async def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint from the current content of a notebook.""" - path = path.strip("/") - # only the one checkpoint ID: - checkpoint_id = "checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - await self._save_notebook(os_checkpoint_path, nb) - - # return the checkpoint info - return await self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - async def get_notebook_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a notebook.""" - path = path.strip("/") - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - return { - "type": "notebook", - "content": await self._read_notebook( - os_checkpoint_path, - as_version=4, - ), - } - - async def get_file_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a file.""" - path = path.strip("/") - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - content, format = await self._read_file(os_checkpoint_path, format=None) - return { - "type": "file", - "content": content, - "format": format, - } diff --git a/server/jupyter_server/services/contents/fileio.py b/server/jupyter_server/services/contents/fileio.py deleted file mode 100644 index 4910433..0000000 --- a/server/jupyter_server/services/contents/fileio.py +++ /dev/null @@ -1,431 +0,0 @@ -""" -Utilities for file-based Contents/Checkpoints managers. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import errno -import io -import os -import shutil -from base64 import decodebytes -from base64 import encodebytes -from contextlib import contextmanager -from functools import partial - -import nbformat -from anyio.to_thread import run_sync -from tornado.web import HTTPError -from traitlets import Bool -from traitlets.config import Configurable - -from jupyter_server.utils import to_api_path -from jupyter_server.utils import to_os_path - - -def replace_file(src, dst): - """replace dst with src""" - os.replace(src, dst) - - -async def async_replace_file(src, dst): - """replace dst with src asynchronously""" - await run_sync(os.replace, src, dst) - - -def copy2_safe(src, dst, log=None): - """copy src to dst - - like shutil.copy2, but log errors in copystat instead of raising - """ - shutil.copyfile(src, dst) - try: - shutil.copystat(src, dst) - except OSError: - if log: - log.debug("copystat on %s failed", dst, exc_info=True) - - -async def async_copy2_safe(src, dst, log=None): - """copy src to dst asynchronously - - like shutil.copy2, but log errors in copystat instead of raising - """ - await run_sync(shutil.copyfile, src, dst) - try: - await run_sync(shutil.copystat, src, dst) - except OSError: - if log: - log.debug("copystat on %s failed", dst, exc_info=True) - - -def path_to_intermediate(path): - """Name of the intermediate file used in atomic writes. - - The .~ prefix will make Dropbox ignore the temporary file.""" - dirname, basename = os.path.split(path) - return os.path.join(dirname, ".~" + basename) - - -def path_to_invalid(path): - """Name of invalid file after a failed atomic write and subsequent read.""" - dirname, basename = os.path.split(path) - return os.path.join(dirname, basename + ".invalid") - - -@contextmanager -def atomic_writing(path, text=True, encoding="utf-8", log=None, **kwargs): - """Context manager to write to a file only if the entire write is successful. - - This works by copying the previous file contents to a temporary file in the - same directory, and renaming that file back to the target if the context - exits with an error. If the context is successful, the new data is synced to - disk and the temporary file is removed. - - Parameters - ---------- - path : str - The target file to write to. - text : bool, optional - Whether to open the file in text mode (i.e. to write unicode). Default is - True. - encoding : str, optional - The encoding to use for files opened in text mode. Default is UTF-8. - **kwargs - Passed to :func:`io.open`. - """ - # realpath doesn't work on Windows: https://bugs.python.org/issue9949 - # Luckily, we only need to resolve the file itself being a symlink, not - # any of its directories, so this will suffice: - if os.path.islink(path): - path = os.path.join(os.path.dirname(path), os.readlink(path)) - - tmp_path = path_to_intermediate(path) - - if os.path.isfile(path): - copy2_safe(path, tmp_path, log=log) - - if text: - # Make sure that text files have Unix linefeeds by default - kwargs.setdefault("newline", "\n") - fileobj = io.open(path, "w", encoding=encoding, **kwargs) - else: - fileobj = io.open(path, "wb", **kwargs) - - try: - yield fileobj - except: - # Failed! Move the backup file back to the real path to avoid corruption - fileobj.close() - replace_file(tmp_path, path) - raise - - # Flush to disk - fileobj.flush() - os.fsync(fileobj.fileno()) - fileobj.close() - - # Written successfully, now remove the backup copy - if os.path.isfile(tmp_path): - os.remove(tmp_path) - - -@contextmanager -def _simple_writing(path, text=True, encoding="utf-8", log=None, **kwargs): - """Context manager to write file without doing atomic writing - (for weird filesystem eg: nfs). - - Parameters - ---------- - path : str - The target file to write to. - text : bool, optional - Whether to open the file in text mode (i.e. to write unicode). Default is - True. - encoding : str, optional - The encoding to use for files opened in text mode. Default is UTF-8. - **kwargs - Passed to :func:`io.open`. - """ - # realpath doesn't work on Windows: https://bugs.python.org/issue9949 - # Luckily, we only need to resolve the file itself being a symlink, not - # any of its directories, so this will suffice: - if os.path.islink(path): - path = os.path.join(os.path.dirname(path), os.readlink(path)) - - if text: - # Make sure that text files have Unix linefeeds by default - kwargs.setdefault("newline", "\n") - fileobj = io.open(path, "w", encoding=encoding, **kwargs) - else: - fileobj = io.open(path, "wb", **kwargs) - - try: - yield fileobj - except: - fileobj.close() - raise - - fileobj.close() - - -class FileManagerMixin(Configurable): - """ - Mixin for ContentsAPI classes that interact with the filesystem. - - Provides facilities for reading, writing, and copying files. - - Shared by FileContentsManager and FileCheckpoints. - - Note - ---- - Classes using this mixin must provide the following attributes: - - root_dir : unicode - A directory against against which API-style paths are to be resolved. - - log : logging.Logger - """ - - use_atomic_writing = Bool( - True, - config=True, - help="""By default notebooks are saved on disk on a temporary file and then if succefully written, it replaces the old ones. - This procedure, namely 'atomic_writing', causes some bugs on file system whitout operation order enforcement (like some networked fs). - If set to False, the new notebook is written directly on the old one which could fail (eg: full filesystem or quota )""", - ) - - @contextmanager - def open(self, os_path, *args, **kwargs): - """wrapper around io.open that turns permission errors into 403""" - with self.perm_to_403(os_path): - with io.open(os_path, *args, **kwargs) as f: - yield f - - @contextmanager - def atomic_writing(self, os_path, *args, **kwargs): - """wrapper around atomic_writing that turns permission errors to 403. - Depending on flag 'use_atomic_writing', the wrapper perform an actual atomic writing or - simply writes the file (whatever an old exists or not)""" - with self.perm_to_403(os_path): - if self.use_atomic_writing: - with atomic_writing(os_path, *args, log=self.log, **kwargs) as f: - yield f - else: - with _simple_writing(os_path, *args, log=self.log, **kwargs) as f: - yield f - - @contextmanager - def perm_to_403(self, os_path=""): - """context manager for turning permission errors into 403.""" - try: - yield - except (OSError, IOError) as e: - if e.errno in {errno.EPERM, errno.EACCES}: - # make 403 error message without root prefix - # this may not work perfectly on unicode paths on Python 2, - # but nobody should be doing that anyway. - if not os_path: - os_path = e.filename or "unknown file" - path = to_api_path(os_path, root=self.root_dir) - raise HTTPError(403, "Permission denied: %s" % path) from e - else: - raise - - def _copy(self, src, dest): - """copy src to dest - - like shutil.copy2, but log errors in copystat - """ - copy2_safe(src, dest, log=self.log) - - def _get_os_path(self, path): - """Given an API path, return its file system path. - - Parameters - ---------- - path : string - The relative API path to the named file. - - Returns - ------- - path : string - Native, absolute OS path to for a file. - - Raises - ------ - 404: if path is outside root - """ - root = os.path.abspath(self.root_dir) - os_path = to_os_path(path, root) - if not (os.path.abspath(os_path) + os.path.sep).startswith(root): - raise HTTPError(404, "%s is outside root contents directory" % path) - return os_path - - def _read_notebook(self, os_path, as_version=4): - """Read a notebook from an os path.""" - with self.open(os_path, "r", encoding="utf-8") as f: - try: - return nbformat.read(f, as_version=as_version) - except Exception as e: - e_orig = e - - # If use_atomic_writing is enabled, we'll guess that it was also - # enabled when this notebook was written and look for a valid - # atomic intermediate. - tmp_path = path_to_intermediate(os_path) - - if not self.use_atomic_writing or not os.path.exists(tmp_path): - raise HTTPError( - 400, - "Unreadable Notebook: %s %r" % (os_path, e_orig), - ) - - # Move the bad file aside, restore the intermediate, and try again. - invalid_file = path_to_invalid(os_path) - replace_file(os_path, invalid_file) - replace_file(tmp_path, os_path) - return self._read_notebook(os_path, as_version) - - def _save_notebook(self, os_path, nb): - """Save a notebook to an os_path.""" - with self.atomic_writing(os_path, encoding="utf-8") as f: - nbformat.write(nb, f, version=nbformat.NO_CONVERT) - - def _read_file(self, os_path, format): - """Read a non-notebook file. - - os_path: The path to be read. - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - if not os.path.isfile(os_path): - raise HTTPError(400, "Cannot read non-file %s" % os_path) - - with self.open(os_path, "rb") as f: - bcontent = f.read() - - if format is None or format == "text": - # Try to interpret as unicode if format is unknown or if unicode - # was explicitly requested. - try: - return bcontent.decode("utf8"), "text" - except UnicodeError as e: - if format == "text": - raise HTTPError( - 400, - "%s is not UTF-8 encoded" % os_path, - reason="bad format", - ) from e - return encodebytes(bcontent).decode("ascii"), "base64" - - def _save_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {"text", "base64"}: - raise HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == "text": - bcontent = content.encode("utf8") - else: - b64_bytes = content.encode("ascii") - bcontent = decodebytes(b64_bytes) - except Exception as e: - raise HTTPError(400, "Encoding error saving %s: %s" % (os_path, e)) from e - - with self.atomic_writing(os_path, text=False) as f: - f.write(bcontent) - - -class AsyncFileManagerMixin(FileManagerMixin): - """ - Mixin for ContentsAPI classes that interact with the filesystem asynchronously. - """ - - async def _copy(self, src, dest): - """copy src to dest - - like shutil.copy2, but log errors in copystat - """ - await async_copy2_safe(src, dest, log=self.log) - - async def _read_notebook(self, os_path, as_version=4): - """Read a notebook from an os path.""" - with self.open(os_path, "r", encoding="utf-8") as f: - try: - return await run_sync(partial(nbformat.read, as_version=as_version), f) - except Exception as e: - e_orig = e - - # If use_atomic_writing is enabled, we'll guess that it was also - # enabled when this notebook was written and look for a valid - # atomic intermediate. - tmp_path = path_to_intermediate(os_path) - - if not self.use_atomic_writing or not os.path.exists(tmp_path): - raise HTTPError( - 400, - "Unreadable Notebook: %s %r" % (os_path, e_orig), - ) - - # Move the bad file aside, restore the intermediate, and try again. - invalid_file = path_to_invalid(os_path) - await async_replace_file(os_path, invalid_file) - await async_replace_file(tmp_path, os_path) - return await self._read_notebook(os_path, as_version) - - async def _save_notebook(self, os_path, nb): - """Save a notebook to an os_path.""" - with self.atomic_writing(os_path, encoding="utf-8") as f: - await run_sync(partial(nbformat.write, version=nbformat.NO_CONVERT), nb, f) - - async def _read_file(self, os_path, format): - """Read a non-notebook file. - - os_path: The path to be read. - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - if not os.path.isfile(os_path): - raise HTTPError(400, "Cannot read non-file %s" % os_path) - - with self.open(os_path, "rb") as f: - bcontent = await run_sync(f.read) - - if format is None or format == "text": - # Try to interpret as unicode if format is unknown or if unicode - # was explicitly requested. - try: - return bcontent.decode("utf8"), "text" - except UnicodeError as e: - if format == "text": - raise HTTPError( - 400, - "%s is not UTF-8 encoded" % os_path, - reason="bad format", - ) from e - return encodebytes(bcontent).decode("ascii"), "base64" - - async def _save_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {"text", "base64"}: - raise HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == "text": - bcontent = content.encode("utf8") - else: - b64_bytes = content.encode("ascii") - bcontent = decodebytes(b64_bytes) - except Exception as e: - raise HTTPError(400, "Encoding error saving %s: %s" % (os_path, e)) from e - - with self.atomic_writing(os_path, text=False) as f: - await run_sync(f.write, bcontent) diff --git a/server/jupyter_server/services/contents/filemanager.py b/server/jupyter_server/services/contents/filemanager.py deleted file mode 100644 index 5540875..0000000 --- a/server/jupyter_server/services/contents/filemanager.py +++ /dev/null @@ -1,908 +0,0 @@ -"""A contents manager that uses the local file system for storage.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import errno -import mimetypes -import os -import shutil -import stat -import sys -from datetime import datetime - -import nbformat -from anyio.to_thread import run_sync -from ipython_genutils.importstring import import_item -from jupyter_core.paths import exists -from jupyter_core.paths import is_file_hidden -from jupyter_core.paths import is_hidden -from send2trash import send2trash -from tornado import web -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import TraitError -from traitlets import Unicode -from traitlets import validate - -from .filecheckpoints import AsyncFileCheckpoints -from .filecheckpoints import FileCheckpoints -from .fileio import AsyncFileManagerMixin -from .fileio import FileManagerMixin -from .manager import AsyncContentsManager -from .manager import ContentsManager -from jupyter_server import _tz as tz -from jupyter_server.base.handlers import AuthenticatedFileHandler -from jupyter_server.transutils import _i18n - -try: - from os.path import samefile -except ImportError: - # windows + py2 - from jupyter_server.utils import samefile_simple as samefile - -_script_exporter = None - - -class FileContentsManager(FileManagerMixin, ContentsManager): - - root_dir = Unicode(config=True) - - @default("root_dir") - def _default_root_dir(self): - try: - return self.parent.root_dir - except AttributeError: - return os.getcwd() - - post_save_hook = Any( - None, - config=True, - allow_none=True, - help="""Python callable or importstring thereof - - to be called on the path of a file just saved. - - This can be used to process the file on disk, - such as converting the notebook to a script or HTML via nbconvert. - - It will be called as (all arguments passed by keyword):: - - hook(os_path=os_path, model=model, contents_manager=instance) - - - path: the filesystem path to the file just written - - model: the model representing the file - - contents_manager: this ContentsManager instance - """, - ) - - @validate("post_save_hook") - def _validate_post_save_hook(self, proposal): - value = proposal["value"] - if isinstance(value, str): - value = import_item(value) - if not callable(value): - raise TraitError("post_save_hook must be callable") - return value - - def run_post_save_hook(self, model, os_path): - """Run the post-save hook if defined, and log errors""" - if self.post_save_hook: - try: - self.log.debug("Running post-save hook on %s", os_path) - self.post_save_hook(os_path=os_path, model=model, contents_manager=self) - except Exception as e: - self.log.error("Post-save hook failed o-n %s", os_path, exc_info=True) - raise web.HTTPError( - 500, "Unexpected error while running post hook save: %s" % e - ) from e - - @validate("root_dir") - def _validate_root_dir(self, proposal): - """Do a bit of validation of the root_dir.""" - value = proposal["value"] - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - if not os.path.isdir(value): - raise TraitError("%r is not a directory" % value) - return value - - @default("checkpoints_class") - def _checkpoints_class_default(self): - return FileCheckpoints - - delete_to_trash = Bool( - True, - config=True, - help="""If True (default), deleting files will send them to the - platform's trash/recycle bin, where they can be recovered. If False, - deleting files really deletes them.""", - ) - - always_delete_dir = Bool( - False, - config=True, - help="""If True, deleting a non-empty directory will always be allowed. - WARNING this may result in files being permanently removed; e.g. on Windows, - if the data size is too big for the trash/recycle bin the directory will be permanently - deleted. If False (default), the non-empty directory will be sent to the trash only - if safe. And if ``delete_to_trash`` is True, the directory won't be deleted.""", - ) - - @default("files_handler_class") - def _files_handler_class_default(self): - return AuthenticatedFileHandler - - @default("files_handler_params") - def _files_handler_params_default(self): - return {"path": self.root_dir} - - def is_hidden(self, path): - """Does the API style path correspond to a hidden directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root_dir). - - Returns - ------- - hidden : bool - Whether the path exists and is hidden. - """ - path = path.strip("/") - os_path = self._get_os_path(path=path) - return is_hidden(os_path, self.root_dir) - - def is_writable(self, path): - """Does the API style path correspond to a writable directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root_dir). - - Returns - ------- - hidden : bool - Whether the path exists and is writable. - """ - path = path.strip("/") - os_path = self._get_os_path(path=path) - try: - return os.access(os_path, os.W_OK) - except OSError: - self.log.error("Failed to check write permissions on %s", os_path) - return False - - def file_exists(self, path): - """Returns True if the file exists, else returns False. - - API-style wrapper for os.path.isfile - - Parameters - ---------- - path : string - The relative path to the file (with '/' as separator) - - Returns - ------- - exists : bool - Whether the file exists. - """ - path = path.strip("/") - os_path = self._get_os_path(path) - return os.path.isfile(os_path) - - def dir_exists(self, path): - """Does the API-style path refer to an extant directory? - - API-style wrapper for os.path.isdir - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root_dir). - - Returns - ------- - exists : bool - Whether the path is indeed a directory. - """ - path = path.strip("/") - os_path = self._get_os_path(path=path) - return os.path.isdir(os_path) - - def exists(self, path): - """Returns True if the path exists, else returns False. - - API-style wrapper for os.path.exists - - Parameters - ---------- - path : string - The API path to the file (with '/' as separator) - - Returns - ------- - exists : bool - Whether the target exists. - """ - path = path.strip("/") - os_path = self._get_os_path(path=path) - return exists(os_path) - - def _base_model(self, path): - """Build the common base of a contents model""" - os_path = self._get_os_path(path) - info = os.lstat(os_path) - - try: - # size of file - size = info.st_size - except (ValueError, OSError): - self.log.warning("Unable to get size.") - size = None - - try: - last_modified = tz.utcfromtimestamp(info.st_mtime) - except (ValueError, OSError): - # Files can rarely have an invalid timestamp - # https://github.com/jupyter/notebook/issues/2539 - # https://github.com/jupyter/notebook/issues/2757 - # Use the Unix epoch as a fallback so we don't crash. - self.log.warning("Invalid mtime %s for %s", info.st_mtime, os_path) - last_modified = datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC) - - try: - created = tz.utcfromtimestamp(info.st_ctime) - except (ValueError, OSError): # See above - self.log.warning("Invalid ctime %s for %s", info.st_ctime, os_path) - created = datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC) - - # Create the base model. - model = {} - model["name"] = path.rsplit("/", 1)[-1] - model["path"] = path - model["last_modified"] = last_modified - model["created"] = created - model["content"] = None - model["format"] = None - model["mimetype"] = None - model["size"] = size - model["writable"] = self.is_writable(path) - - return model - - def _dir_model(self, path, content=True): - """Build a model for a directory - - if content is requested, will include a listing of the directory - """ - os_path = self._get_os_path(path) - - four_o_four = "directory does not exist: %r" % path - - if not os.path.isdir(os_path): - raise web.HTTPError(404, four_o_four) - elif is_hidden(os_path, self.root_dir) and not self.allow_hidden: - self.log.info("Refusing to serve hidden directory %r, via 404 Error", os_path) - raise web.HTTPError(404, four_o_four) - - model = self._base_model(path) - model["type"] = "directory" - model["size"] = None - if content: - model["content"] = contents = [] - os_dir = self._get_os_path(path) - for name in os.listdir(os_dir): - try: - os_path = os.path.join(os_dir, name) - except UnicodeDecodeError as e: - self.log.warning("failed to decode filename '%s': %s", name, e) - continue - - try: - st = os.lstat(os_path) - except OSError as e: - # skip over broken symlinks in listing - if e.errno == errno.ENOENT: - self.log.warning("%s doesn't exist", os_path) - elif e.errno != errno.EACCES: # Don't provide clues about protected files - self.log.warning("Error stat-ing %s: %s", os_path, e) - continue - - if ( - not stat.S_ISLNK(st.st_mode) - and not stat.S_ISREG(st.st_mode) - and not stat.S_ISDIR(st.st_mode) - ): - self.log.debug("%s not a regular file", os_path) - continue - - try: - if self.should_list(name): - if self.allow_hidden or not is_file_hidden(os_path, stat_res=st): - contents.append(self.get(path="%s/%s" % (path, name), content=False)) - except OSError as e: - # ELOOP: recursive symlink, also don't show failure due to permissions - if e.errno not in [errno.ELOOP, errno.EACCES]: - self.log.warning( - "Unknown error checking if file %r is hidden", - os_path, - exc_info=True, - ) - - model["format"] = "json" - - return model - - def _file_model(self, path, content=True, format=None): - """Build a model for a file - - if content is requested, include the file contents. - - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - model = self._base_model(path) - model["type"] = "file" - - os_path = self._get_os_path(path) - model["mimetype"] = mimetypes.guess_type(os_path)[0] - - if content: - content, format = self._read_file(os_path, format) - if model["mimetype"] is None: - default_mime = { - "text": "text/plain", - "base64": "application/octet-stream", - }[format] - model["mimetype"] = default_mime - - model.update( - content=content, - format=format, - ) - - return model - - def _notebook_model(self, path, content=True): - """Build a notebook model - - if content is requested, the notebook content will be populated - as a JSON structure (not double-serialized) - """ - model = self._base_model(path) - model["type"] = "notebook" - os_path = self._get_os_path(path) - - if content: - nb = self._read_notebook(os_path, as_version=4) - self.mark_trusted_cells(nb, path) - model["content"] = nb - model["format"] = "json" - self.validate_notebook_model(model) - - return model - - def get(self, path, content=True, type=None, format=None): - """Takes a path for an entity and returns its model - - Parameters - ---------- - path : str - the API path that describes the relative path for the target - content : bool - Whether to include the contents in the reply - type : str, optional - The requested type - 'file', 'notebook', or 'directory'. - Will raise HTTPError 400 if the content doesn't match. - format : str, optional - The requested format for file contents. 'text' or 'base64'. - Ignored if this returns a notebook or directory model. - - Returns - ------- - model : dict - the contents model. If content=True, returns the contents - of the file or directory as well. - """ - path = path.strip("/") - - if not self.exists(path): - raise web.HTTPError(404, "No such file or directory: %s" % path) - - os_path = self._get_os_path(path) - if os.path.isdir(os_path): - if type not in (None, "directory"): - raise web.HTTPError( - 400, - "%s is a directory, not a %s" % (path, type), - reason="bad type", - ) - model = self._dir_model(path, content=content) - elif type == "notebook" or (type is None and path.endswith(".ipynb")): - model = self._notebook_model(path, content=content) - else: - if type == "directory": - raise web.HTTPError(400, "%s is not a directory" % path, reason="bad type") - model = self._file_model(path, content=content, format=format) - return model - - def _save_directory(self, os_path, model, path=""): - """create a directory""" - if is_hidden(os_path, self.root_dir) and not self.allow_hidden: - raise web.HTTPError(400, "Cannot create hidden directory %r" % os_path) - if not os.path.exists(os_path): - with self.perm_to_403(): - os.mkdir(os_path) - elif not os.path.isdir(os_path): - raise web.HTTPError(400, "Not a directory: %s" % (os_path)) - else: - self.log.debug("Directory %r already exists", os_path) - - def save(self, model, path=""): - """Save the file model and return the model with no content.""" - path = path.strip("/") - - self.run_pre_save_hook(model=model, path=path) - - if "type" not in model: - raise web.HTTPError(400, "No file type provided") - if "content" not in model and model["type"] != "directory": - raise web.HTTPError(400, "No file content provided") - - os_path = self._get_os_path(path) - self.log.debug("Saving %s", os_path) - - try: - if model["type"] == "notebook": - nb = nbformat.from_dict(model["content"]) - self.check_and_sign(nb, path) - self._save_notebook(os_path, nb) - # One checkpoint should always exist for notebooks. - if not self.checkpoints.list_checkpoints(path): - self.create_checkpoint(path) - elif model["type"] == "file": - # Missing format will be handled internally by _save_file. - self._save_file(os_path, model["content"], model.get("format")) - elif model["type"] == "directory": - self._save_directory(os_path, model, path) - else: - raise web.HTTPError(400, "Unhandled contents type: %s" % model["type"]) - except web.HTTPError: - raise - except Exception as e: - self.log.error("Error while saving file: %s %s", path, e, exc_info=True) - raise web.HTTPError(500, "Unexpected error while saving file: %s %s" % (path, e)) from e - - validation_message = None - if model["type"] == "notebook": - self.validate_notebook_model(model) - validation_message = model.get("message", None) - - model = self.get(path, content=False) - if validation_message: - model["message"] = validation_message - - self.run_post_save_hook(model=model, os_path=os_path) - - return model - - def delete_file(self, path): - """Delete file at path.""" - path = path.strip("/") - os_path = self._get_os_path(path) - rm = os.unlink - if not os.path.exists(os_path): - raise web.HTTPError(404, "File or directory does not exist: %s" % os_path) - - def _check_trash(os_path): - if sys.platform in {"win32", "darwin"}: - return True - - # It's a bit more nuanced than this, but until we can better - # distinguish errors from send2trash, assume that we can only trash - # files on the same partition as the home directory. - file_dev = os.stat(os_path).st_dev - home_dev = os.stat(os.path.expanduser("~")).st_dev - return file_dev == home_dev - - def is_non_empty_dir(os_path): - if os.path.isdir(os_path): - # A directory containing only leftover checkpoints is - # considered empty. - cp_dir = getattr(self.checkpoints, "checkpoint_dir", None) - if set(os.listdir(os_path)) - {cp_dir}: - return True - - return False - - if self.delete_to_trash: - if not self.always_delete_dir and sys.platform == "win32" and is_non_empty_dir(os_path): - # send2trash can really delete files on Windows, so disallow - # deleting non-empty files. See Github issue 3631. - raise web.HTTPError(400, "Directory %s not empty" % os_path) - if _check_trash(os_path): - # Looking at the code in send2trash, I don't think the errors it - # raises let us distinguish permission errors from other errors in - # code. So for now, the "look before you leap" approach is used. - if not self.is_writable(path): - raise web.HTTPError(403, "Permission denied: %s" % path) - self.log.debug("Sending %s to trash", os_path) - send2trash(os_path) - return - else: - self.log.warning( - "Skipping trash for %s, on different device " "to home directory", - os_path, - ) - - if os.path.isdir(os_path): - # Don't permanently delete non-empty directories. - if not self.always_delete_dir and is_non_empty_dir(os_path): - raise web.HTTPError(400, "Directory %s not empty" % os_path) - self.log.debug("Removing directory %s", os_path) - with self.perm_to_403(): - shutil.rmtree(os_path) - else: - self.log.debug("Unlinking file %s", os_path) - with self.perm_to_403(): - rm(os_path) - - def rename_file(self, old_path, new_path): - """Rename a file.""" - old_path = old_path.strip("/") - new_path = new_path.strip("/") - if new_path == old_path: - return - - new_os_path = self._get_os_path(new_path) - old_os_path = self._get_os_path(old_path) - - # Should we proceed with the move? - if os.path.exists(new_os_path) and not samefile(old_os_path, new_os_path): - raise web.HTTPError(409, "File already exists: %s" % new_path) - - # Move the file - try: - with self.perm_to_403(): - shutil.move(old_os_path, new_os_path) - except web.HTTPError: - raise - except Exception as e: - raise web.HTTPError(500, "Unknown error renaming file: %s %s" % (old_path, e)) from e - - def info_string(self): - return _i18n("Serving notebooks from local directory: %s") % self.root_dir - - def get_kernel_path(self, path, model=None): - """Return the initial API path of a kernel associated with a given notebook""" - if self.dir_exists(path): - return path - if "/" in path: - parent_dir = path.rsplit("/", 1)[0] - else: - parent_dir = "" - return parent_dir - - -class AsyncFileContentsManager(FileContentsManager, AsyncFileManagerMixin, AsyncContentsManager): - @default("checkpoints_class") - def _checkpoints_class_default(self): - return AsyncFileCheckpoints - - async def _dir_model(self, path, content=True): - """Build a model for a directory - - if content is requested, will include a listing of the directory - """ - os_path = self._get_os_path(path) - - four_o_four = "directory does not exist: %r" % path - - if not os.path.isdir(os_path): - raise web.HTTPError(404, four_o_four) - elif is_hidden(os_path, self.root_dir) and not self.allow_hidden: - self.log.info("Refusing to serve hidden directory %r, via 404 Error", os_path) - raise web.HTTPError(404, four_o_four) - - model = self._base_model(path) - model["type"] = "directory" - model["size"] = None - if content: - model["content"] = contents = [] - os_dir = self._get_os_path(path) - dir_contents = await run_sync(os.listdir, os_dir) - for name in dir_contents: - try: - os_path = os.path.join(os_dir, name) - except UnicodeDecodeError as e: - self.log.warning("failed to decode filename '%s': %s", name, e) - continue - - try: - st = await run_sync(os.lstat, os_path) - except OSError as e: - # skip over broken symlinks in listing - if e.errno == errno.ENOENT: - self.log.warning("%s doesn't exist", os_path) - elif e.errno != errno.EACCES: # Don't provide clues about protected files - self.log.warning("Error stat-ing %s: %s", os_path, e) - continue - - if ( - not stat.S_ISLNK(st.st_mode) - and not stat.S_ISREG(st.st_mode) - and not stat.S_ISDIR(st.st_mode) - ): - self.log.debug("%s not a regular file", os_path) - continue - - try: - if self.should_list(name): - if self.allow_hidden or not is_file_hidden(os_path, stat_res=st): - contents.append( - await self.get(path="%s/%s" % (path, name), content=False) - ) - except OSError as e: - # ELOOP: recursive symlink, also don't show failure due to permissions - if e.errno not in [errno.ELOOP, errno.EACCES]: - self.log.warning( - "Unknown error checking if file %r is hidden", - os_path, - exc_info=True, - ) - - model["format"] = "json" - - return model - - async def _file_model(self, path, content=True, format=None): - """Build a model for a file - - if content is requested, include the file contents. - - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - model = self._base_model(path) - model["type"] = "file" - - os_path = self._get_os_path(path) - model["mimetype"] = mimetypes.guess_type(os_path)[0] - - if content: - content, format = await self._read_file(os_path, format) - if model["mimetype"] is None: - default_mime = { - "text": "text/plain", - "base64": "application/octet-stream", - }[format] - model["mimetype"] = default_mime - - model.update( - content=content, - format=format, - ) - - return model - - async def _notebook_model(self, path, content=True): - """Build a notebook model - - if content is requested, the notebook content will be populated - as a JSON structure (not double-serialized) - """ - model = self._base_model(path) - model["type"] = "notebook" - os_path = self._get_os_path(path) - - if content: - nb = await self._read_notebook(os_path, as_version=4) - self.mark_trusted_cells(nb, path) - model["content"] = nb - model["format"] = "json" - self.validate_notebook_model(model) - - return model - - async def get(self, path, content=True, type=None, format=None): - """Takes a path for an entity and returns its model - - Parameters - ---------- - path : str - the API path that describes the relative path for the target - content : bool - Whether to include the contents in the reply - type : str, optional - The requested type - 'file', 'notebook', or 'directory'. - Will raise HTTPError 400 if the content doesn't match. - format : str, optional - The requested format for file contents. 'text' or 'base64'. - Ignored if this returns a notebook or directory model. - - Returns - ------- - model : dict - the contents model. If content=True, returns the contents - of the file or directory as well. - """ - path = path.strip("/") - - if not self.exists(path): - raise web.HTTPError(404, "No such file or directory: %s" % path) - - os_path = self._get_os_path(path) - if os.path.isdir(os_path): - if type not in (None, "directory"): - raise web.HTTPError( - 400, - "%s is a directory, not a %s" % (path, type), - reason="bad type", - ) - model = await self._dir_model(path, content=content) - elif type == "notebook" or (type is None and path.endswith(".ipynb")): - model = await self._notebook_model(path, content=content) - else: - if type == "directory": - raise web.HTTPError(400, "%s is not a directory" % path, reason="bad type") - model = await self._file_model(path, content=content, format=format) - return model - - async def _save_directory(self, os_path, model, path=""): - """create a directory""" - if is_hidden(os_path, self.root_dir) and not self.allow_hidden: - raise web.HTTPError(400, "Cannot create hidden directory %r" % os_path) - if not os.path.exists(os_path): - with self.perm_to_403(): - await run_sync(os.mkdir, os_path) - elif not os.path.isdir(os_path): - raise web.HTTPError(400, "Not a directory: %s" % (os_path)) - else: - self.log.debug("Directory %r already exists", os_path) - - async def save(self, model, path=""): - """Save the file model and return the model with no content.""" - path = path.strip("/") - - os_path = self._get_os_path(path) - self.log.debug("Saving %s", os_path) - self.run_pre_save_hook(model=model, path=path) - - if "type" not in model: - raise web.HTTPError(400, "No file type provided") - if "content" not in model and model["type"] != "directory": - raise web.HTTPError(400, "No file content provided") - - try: - if model["type"] == "notebook": - nb = nbformat.from_dict(model["content"]) - self.check_and_sign(nb, path) - await self._save_notebook(os_path, nb) - # One checkpoint should always exist for notebooks. - if not (await self.checkpoints.list_checkpoints(path)): - await self.create_checkpoint(path) - elif model["type"] == "file": - # Missing format will be handled internally by _save_file. - await self._save_file(os_path, model["content"], model.get("format")) - elif model["type"] == "directory": - await self._save_directory(os_path, model, path) - else: - raise web.HTTPError(400, "Unhandled contents type: %s" % model["type"]) - except web.HTTPError: - raise - except Exception as e: - self.log.error("Error while saving file: %s %s", path, e, exc_info=True) - raise web.HTTPError(500, "Unexpected error while saving file: %s %s" % (path, e)) from e - - validation_message = None - if model["type"] == "notebook": - self.validate_notebook_model(model) - validation_message = model.get("message", None) - - model = await self.get(path, content=False) - if validation_message: - model["message"] = validation_message - - self.run_post_save_hook(model=model, os_path=os_path) - - return model - - async def delete_file(self, path): - """Delete file at path.""" - path = path.strip("/") - os_path = self._get_os_path(path) - rm = os.unlink - if not os.path.exists(os_path): - raise web.HTTPError(404, "File or directory does not exist: %s" % os_path) - - async def _check_trash(os_path): - if sys.platform in {"win32", "darwin"}: - return True - - # It's a bit more nuanced than this, but until we can better - # distinguish errors from send2trash, assume that we can only trash - # files on the same partition as the home directory. - file_dev = (await run_sync(os.stat, os_path)).st_dev - home_dev = (await run_sync(os.stat, os.path.expanduser("~"))).st_dev - return file_dev == home_dev - - async def is_non_empty_dir(os_path): - if os.path.isdir(os_path): - # A directory containing only leftover checkpoints is - # considered empty. - cp_dir = getattr(self.checkpoints, "checkpoint_dir", None) - dir_contents = set(await run_sync(os.listdir, os_path)) - if dir_contents - {cp_dir}: - return True - - return False - - if self.delete_to_trash: - if ( - not self.always_delete_dir - and sys.platform == "win32" - and await is_non_empty_dir(os_path) - ): - # send2trash can really delete files on Windows, so disallow - # deleting non-empty files. See Github issue 3631. - raise web.HTTPError(400, "Directory %s not empty" % os_path) - if await _check_trash(os_path): - # Looking at the code in send2trash, I don't think the errors it - # raises let us distinguish permission errors from other errors in - # code. So for now, the "look before you leap" approach is used. - if not self.is_writable(path): - raise web.HTTPError(403, "Permission denied: %s" % path) - self.log.debug("Sending %s to trash", os_path) - send2trash(os_path) - return - else: - self.log.warning( - "Skipping trash for %s, on different device " "to home directory", - os_path, - ) - - if os.path.isdir(os_path): - # Don't permanently delete non-empty directories. - if not self.always_delete_dir and await is_non_empty_dir(os_path): - raise web.HTTPError(400, "Directory %s not empty" % os_path) - self.log.debug("Removing directory %s", os_path) - with self.perm_to_403(): - await run_sync(shutil.rmtree, os_path) - else: - self.log.debug("Unlinking file %s", os_path) - with self.perm_to_403(): - await run_sync(rm, os_path) - - async def rename_file(self, old_path, new_path): - """Rename a file.""" - old_path = old_path.strip("/") - new_path = new_path.strip("/") - if new_path == old_path: - return - - new_os_path = self._get_os_path(new_path) - old_os_path = self._get_os_path(old_path) - - # Should we proceed with the move? - if os.path.exists(new_os_path) and not samefile(old_os_path, new_os_path): - raise web.HTTPError(409, "File already exists: %s" % new_path) - - # Move the file - try: - with self.perm_to_403(): - await run_sync(shutil.move, old_os_path, new_os_path) - except web.HTTPError: - raise - except Exception as e: - raise web.HTTPError(500, "Unknown error renaming file: %s %s" % (old_path, e)) from e diff --git a/server/jupyter_server/services/contents/handlers.py b/server/jupyter_server/services/contents/handlers.py deleted file mode 100644 index 83db1f9..0000000 --- a/server/jupyter_server/services/contents/handlers.py +++ /dev/null @@ -1,340 +0,0 @@ -"""Tornado handlers for the contents web service. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-27%3A-Contents-Service -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json - -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import date_default as json_default -from tornado import web - -from jupyter_server.base.handlers import APIHandler -from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.base.handlers import path_regex -from jupyter_server.utils import ensure_async -from jupyter_server.utils import url_escape -from jupyter_server.utils import url_path_join -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "contents" - - -def validate_model(model, expect_content): - """ - Validate a model returned by a ContentsManager method. - - If expect_content is True, then we expect non-null entries for 'content' - and 'format'. - """ - required_keys = { - "name", - "path", - "type", - "writable", - "created", - "last_modified", - "mimetype", - "content", - "format", - } - missing = required_keys - set(model.keys()) - if missing: - raise web.HTTPError( - 500, - "Missing Model Keys: {missing}".format(missing=missing), - ) - - maybe_none_keys = ["content", "format"] - if expect_content: - errors = [key for key in maybe_none_keys if model[key] is None] - if errors: - raise web.HTTPError( - 500, - "Keys unexpectedly None: {keys}".format(keys=errors), - ) - else: - errors = {key: model[key] for key in maybe_none_keys if model[key] is not None} - if errors: - raise web.HTTPError( - 500, - "Keys unexpectedly not None: {keys}".format(keys=errors), - ) - - -class ContentsAPIHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - -class ContentsHandler(ContentsAPIHandler): - def location_url(https://github.com/self,%20path): - """Return the full URL location of a file. - - Parameters - ---------- - path : unicode - The API path of the file, such as "foo/bar.txt". - """ - return url_path_join(self.base_url, "api", "contents", url_escape(path)) - - def _finish_model(self, model, location=True): - """Finish a JSON request with a model, setting relevant headers, etc.""" - if location: - location = self.location_url(https://github.com/model[%22path%22]) - self.set_header("Location", location) - self.set_header("Last-Modified", model["last_modified"]) - self.set_header("Content-Type", "application/json") - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @authorized - async def get(self, path=""): - """Return a model for a file or directory. - - A directory model contains a list of models (without content) - of the files and directories it contains. - """ - path = path or "" - type = self.get_query_argument("type", default=None) - if type not in {None, "directory", "file", "notebook"}: - raise web.HTTPError(400, "Type %r is invalid" % type) - - format = self.get_query_argument("format", default=None) - if format not in {None, "text", "base64"}: - raise web.HTTPError(400, "Format %r is invalid" % format) - content = self.get_query_argument("content", default="1") - if content not in {"0", "1"}: - raise web.HTTPError(400, "Content %r is invalid" % content) - content = int(content) - - model = await ensure_async( - self.contents_manager.get( - path=path, - type=type, - format=format, - content=content, - ) - ) - validate_model(model, expect_content=content) - self._finish_model(model, location=False) - - @web.authenticated - @authorized - async def patch(self, path=""): - """PATCH renames a file or directory without re-uploading content.""" - cm = self.contents_manager - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, "JSON body missing") - model = await ensure_async(cm.update(model, path)) - validate_model(model, expect_content=False) - self._finish_model(model) - - async def _copy(self, copy_from, copy_to=None): - """Copy a file, optionally specifying a target directory.""" - self.log.info( - "Copying {copy_from} to {copy_to}".format( - copy_from=copy_from, - copy_to=copy_to or "", - ) - ) - model = await ensure_async(self.contents_manager.copy(copy_from, copy_to)) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - async def _upload(self, model, path): - """Handle upload of a new file to path""" - self.log.info("Uploading file to %s", path) - model = await ensure_async(self.contents_manager.new(model, path)) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - async def _new_untitled(self, path, type="", ext=""): - """Create a new, empty untitled entity""" - self.log.info("Creating new %s in %s", type or "file", path) - model = await ensure_async( - self.contents_manager.new_untitled(path=path, type=type, ext=ext) - ) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - async def _save(self, model, path): - """Save an existing file.""" - chunk = model.get("chunk", None) - if not chunk or chunk == -1: # Avoid tedious log information - self.log.info("Saving file at %s", path) - model = await ensure_async(self.contents_manager.save(model, path)) - validate_model(model, expect_content=False) - self._finish_model(model) - - @web.authenticated - @authorized - async def post(self, path=""): - """Create a new file in the specified path. - - POST creates new files. The server always decides on the name. - - POST /api/contents/path - New untitled, empty file or directory. - POST /api/contents/path - with body {"copy_from" : "/path/to/OtherNotebook.ipynb"} - New copy of OtherNotebook in path - """ - - cm = self.contents_manager - - file_exists = await ensure_async(cm.file_exists(path)) - if file_exists: - raise web.HTTPError(400, "Cannot POST to files, use PUT instead.") - - dir_exists = await ensure_async(cm.dir_exists(path)) - if not dir_exists: - raise web.HTTPError(404, "No such directory: %s" % path) - - model = self.get_json_body() - - if model is not None: - copy_from = model.get("copy_from") - ext = model.get("ext", "") - type = model.get("type", "") - if copy_from: - await self._copy(copy_from, path) - else: - await self._new_untitled(path, type=type, ext=ext) - else: - await self._new_untitled(path) - - @web.authenticated - @authorized - async def put(self, path=""): - """Saves the file in the location specified by name and path. - - PUT is very similar to POST, but the requester specifies the name, - whereas with POST, the server picks the name. - - PUT /api/contents/path/Name.ipynb - Save notebook at ``path/Name.ipynb``. Notebook structure is specified - in `content` key of JSON request body. If content is not specified, - create a new empty notebook. - """ - model = self.get_json_body() - if model: - if model.get("copy_from"): - raise web.HTTPError(400, "Cannot copy with PUT, only POST") - exists = await ensure_async(self.contents_manager.file_exists(path)) - if exists: - await self._save(model, path) - else: - await self._upload(model, path) - else: - await self._new_untitled(path) - - @web.authenticated - @authorized - async def delete(self, path=""): - """delete a file in the given path""" - cm = self.contents_manager - self.log.warning("delete %s", path) - await ensure_async(cm.delete(path)) - self.set_status(204) - self.finish() - - -class CheckpointsHandler(ContentsAPIHandler): - @web.authenticated - @authorized - async def get(self, path=""): - """get lists checkpoints for a file""" - cm = self.contents_manager - checkpoints = await ensure_async(cm.list_checkpoints(path)) - data = json.dumps(checkpoints, default=json_default) - self.finish(data) - - @web.authenticated - @authorized - async def post(self, path=""): - """post creates a new checkpoint""" - cm = self.contents_manager - checkpoint = await ensure_async(cm.create_checkpoint(path)) - data = json.dumps(checkpoint, default=json_default) - location = url_path_join( - self.base_url, - "api/contents", - url_escape(path), - "checkpoints", - url_escape(checkpoint["id"]), - ) - self.set_header("Location", location) - self.set_status(201) - self.finish(data) - - -class ModifyCheckpointsHandler(ContentsAPIHandler): - @web.authenticated - @authorized - async def post(self, path, checkpoint_id): - """post restores a file from a checkpoint""" - cm = self.contents_manager - await ensure_async(cm.restore_checkpoint(checkpoint_id, path)) - self.set_status(204) - self.finish() - - @web.authenticated - @authorized - async def delete(self, path, checkpoint_id): - """delete clears a checkpoint for a given file""" - cm = self.contents_manager - await ensure_async(cm.delete_checkpoint(checkpoint_id, path)) - self.set_status(204) - self.finish() - - -class NotebooksRedirectHandler(JupyterHandler): - """Redirect /api/notebooks to /api/contents""" - - SUPPORTED_METHODS = ("GET", "PUT", "PATCH", "POST", "DELETE") - - def get(self, path): - self.log.warning("/api/notebooks is deprecated, use /api/contents") - self.redirect(url_path_join(self.base_url, "api/contents", url_escape(path))) - - put = patch = post = delete = get - - -class TrustNotebooksHandler(JupyterHandler): - """Handles trust/signing of notebooks""" - - @web.authenticated - @authorized(resource=AUTH_RESOURCE) - async def post(self, path=""): - cm = self.contents_manager - await ensure_async(cm.trust_notebook(path)) - self.set_status(201) - self.finish() - - -# ----------------------------------------------------------------------------- -# URL to handler mappings -# ----------------------------------------------------------------------------- - - -_checkpoint_id_regex = r"(?P[\w-]+)" - - -default_handlers = [ - (r"/api/contents%s/checkpoints" % path_regex, CheckpointsHandler), - ( - r"/api/contents%s/checkpoints/%s" % (path_regex, _checkpoint_id_regex), - ModifyCheckpointsHandler, - ), - (r"/api/contents%s/trust" % path_regex, TrustNotebooksHandler), - (r"/api/contents%s" % path_regex, ContentsHandler), - (r"/api/notebooks/?(.*)", NotebooksRedirectHandler), -] diff --git a/server/jupyter_server/services/contents/largefilemanager.py b/server/jupyter_server/services/contents/largefilemanager.py deleted file mode 100644 index 3b404ab..0000000 --- a/server/jupyter_server/services/contents/largefilemanager.py +++ /dev/null @@ -1,150 +0,0 @@ -import base64 -import io -import os - -from anyio.to_thread import run_sync -from tornado import web - -from jupyter_server.services.contents.filemanager import AsyncFileContentsManager -from jupyter_server.services.contents.filemanager import FileContentsManager - - -class LargeFileManager(FileContentsManager): - """Handle large file upload.""" - - def save(self, model, path=""): - """Save the file model and return the model with no content.""" - chunk = model.get("chunk", None) - if chunk is not None: - path = path.strip("/") - - self.run_pre_save_hook(model=model, path=path) - - if "type" not in model: - raise web.HTTPError(400, "No file type provided") - if model["type"] != "file": - raise web.HTTPError( - 400, - 'File type "{}" is not supported for large file transfer'.format(model["type"]), - ) - if "content" not in model and model["type"] != "directory": - raise web.HTTPError(400, "No file content provided") - - os_path = self._get_os_path(path) - self.log.debug("Saving %s", os_path) - - try: - if chunk == 1: - super(LargeFileManager, self)._save_file( - os_path, model["content"], model.get("format") - ) - else: - self._save_large_file(os_path, model["content"], model.get("format")) - except web.HTTPError: - raise - except Exception as e: - self.log.error("Error while saving file: %s %s", path, e, exc_info=True) - raise web.HTTPError( - 500, "Unexpected error while saving file: %s %s" % (path, e) - ) from e - - model = self.get(path, content=False) - - # Last chunk - if chunk == -1: - self.run_post_save_hook(model=model, os_path=os_path) - return model - else: - return super(LargeFileManager, self).save(model, path) - - def _save_large_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {"text", "base64"}: - raise web.HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == "text": - bcontent = content.encode("utf8") - else: - b64_bytes = content.encode("ascii") - bcontent = base64.b64decode(b64_bytes) - except Exception as e: - raise web.HTTPError(400, "Encoding error saving %s: %s" % (os_path, e)) from e - - with self.perm_to_403(os_path): - if os.path.islink(os_path): - os_path = os.path.join(os.path.dirname(os_path), os.readlink(os_path)) - with io.open(os_path, "ab") as f: - f.write(bcontent) - - -class AsyncLargeFileManager(AsyncFileContentsManager): - """Handle large file upload asynchronously""" - - async def save(self, model, path=""): - """Save the file model and return the model with no content.""" - chunk = model.get("chunk", None) - if chunk is not None: - path = path.strip("/") - - os_path = self._get_os_path(path) - self.log.debug("Saving %s", os_path) - self.run_pre_save_hook(model=model, path=path) - - if "type" not in model: - raise web.HTTPError(400, "No file type provided") - if model["type"] != "file": - raise web.HTTPError( - 400, - 'File type "{}" is not supported for large file transfer'.format(model["type"]), - ) - if "content" not in model and model["type"] != "directory": - raise web.HTTPError(400, "No file content provided") - - try: - if chunk == 1: - await super(AsyncLargeFileManager, self)._save_file( - os_path, model["content"], model.get("format") - ) - else: - await self._save_large_file(os_path, model["content"], model.get("format")) - except web.HTTPError: - raise - except Exception as e: - self.log.error("Error while saving file: %s %s", path, e, exc_info=True) - raise web.HTTPError( - 500, "Unexpected error while saving file: %s %s" % (path, e) - ) from e - - model = await self.get(path, content=False) - - # Last chunk - if chunk == -1: - self.run_post_save_hook(model=model, os_path=os_path) - return model - else: - return await super(AsyncLargeFileManager, self).save(model, path) - - async def _save_large_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {"text", "base64"}: - raise web.HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == "text": - bcontent = content.encode("utf8") - else: - b64_bytes = content.encode("ascii") - bcontent = base64.b64decode(b64_bytes) - except Exception as e: - raise web.HTTPError(400, "Encoding error saving %s: %s" % (os_path, e)) from e - - with self.perm_to_403(os_path): - if os.path.islink(os_path): - os_path = os.path.join(os.path.dirname(os_path), os.readlink(os_path)) - with io.open(os_path, "ab") as f: - await run_sync(f.write, bcontent) diff --git a/server/jupyter_server/services/contents/manager.py b/server/jupyter_server/services/contents/manager.py deleted file mode 100644 index 3e47a63..0000000 --- a/server/jupyter_server/services/contents/manager.py +++ /dev/null @@ -1,875 +0,0 @@ -"""A base class for contents managers.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import itertools -import json -import re -from fnmatch import fnmatch - -from ipython_genutils.importstring import import_item -from nbformat import sign -from nbformat import validate as validate_nb -from nbformat import ValidationError -from nbformat.v4 import new_notebook -from tornado.web import HTTPError -from tornado.web import RequestHandler -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import Instance -from traitlets import List -from traitlets import TraitError -from traitlets import Type -from traitlets import Unicode -from traitlets import validate -from traitlets.config.configurable import LoggingConfigurable - -from ...files.handlers import FilesHandler -from .checkpoints import AsyncCheckpoints -from .checkpoints import Checkpoints -from jupyter_server.transutils import _i18n -from jupyter_server.utils import ensure_async - - -copy_pat = re.compile(r"\-Copy\d*\.") - - -class ContentsManager(LoggingConfigurable): - """Base class for serving files and directories. - - This serves any text or binary file, - as well as directories, - with special handling for JSON notebook documents. - - Most APIs take a path argument, - which is always an API-style unicode path, - and always refers to a directory. - - - unicode, not url-escaped - - '/'-separated - - leading and trailing '/' will be stripped - - if unspecified, path defaults to '', - indicating the root path. - - """ - - root_dir = Unicode("/", config=True) - - allow_hidden = Bool(False, config=True, help="Allow access to hidden files") - - notary = Instance(sign.NotebookNotary) - - def _notary_default(self): - return sign.NotebookNotary(parent=self) - - hide_globs = List( - Unicode(), - [ - "__pycache__", - "*.pyc", - "*.pyo", - ".DS_Store", - "*.so", - "*.dylib", - "*~", - ], - config=True, - help=""" - Glob patterns to hide in file and directory listings. - """, - ) - - untitled_notebook = Unicode( - _i18n("Untitled"), - config=True, - help="The base name used when creating untitled notebooks.", - ) - - untitled_file = Unicode( - "untitled", config=True, help="The base name used when creating untitled files." - ) - - untitled_directory = Unicode( - "Untitled Folder", - config=True, - help="The base name used when creating untitled directories.", - ) - - pre_save_hook = Any( - None, - config=True, - allow_none=True, - help="""Python callable or importstring thereof - - To be called on a contents model prior to save. - - This can be used to process the structure, - such as removing notebook outputs or other side effects that - should not be saved. - - It will be called as (all arguments passed by keyword):: - - hook(path=path, model=model, contents_manager=self) - - - model: the model to be saved. Includes file contents. - Modifying this dict will affect the file that is stored. - - path: the API path of the save destination - - contents_manager: this ContentsManager instance - """, - ) - - @validate("pre_save_hook") - def _validate_pre_save_hook(self, proposal): - value = proposal["value"] - if isinstance(value, str): - value = import_item(self.pre_save_hook) - if not callable(value): - raise TraitError("pre_save_hook must be callable") - return value - - def run_pre_save_hook(self, model, path, **kwargs): - """Run the pre-save hook if defined, and log errors""" - if self.pre_save_hook: - try: - self.log.debug("Running pre-save hook on %s", path) - self.pre_save_hook(model=model, path=path, contents_manager=self, **kwargs) - except HTTPError: - # allow custom HTTPErrors to raise, - # rejecting the save with a message. - raise - except Exception: - # unhandled errors don't prevent saving, - # which could cause frustrating data loss - self.log.error("Pre-save hook failed on %s", path, exc_info=True) - - checkpoints_class = Type(Checkpoints, config=True) - checkpoints = Instance(Checkpoints, config=True) - checkpoints_kwargs = Dict(config=True) - - @default("checkpoints") - def _default_checkpoints(self): - return self.checkpoints_class(**self.checkpoints_kwargs) - - @default("checkpoints_kwargs") - def _default_checkpoints_kwargs(self): - return dict( - parent=self, - log=self.log, - ) - - files_handler_class = Type( - FilesHandler, - klass=RequestHandler, - allow_none=True, - config=True, - help="""handler class to use when serving raw file requests. - - Default is a fallback that talks to the ContentsManager API, - which may be inefficient, especially for large files. - - Local files-based ContentsManagers can use a StaticFileHandler subclass, - which will be much more efficient. - - Access to these files should be Authenticated. - """, - ) - - files_handler_params = Dict( - config=True, - help="""Extra parameters to pass to files_handler_class. - - For example, StaticFileHandlers generally expect a `path` argument - specifying the root directory from which to serve files. - """, - ) - - def get_extra_handlers(self): - """Return additional handlers - - Default: self.files_handler_class on /files/.* - """ - handlers = [] - if self.files_handler_class: - handlers.append((r"/files/(.*)", self.files_handler_class, self.files_handler_params)) - return handlers - - # ContentsManager API part 1: methods that must be - # implemented in subclasses. - - def dir_exists(self, path): - """Does a directory exist at the given path? - - Like os.path.isdir - - Override this method in subclasses. - - Parameters - ---------- - path : string - The path to check - - Returns - ------- - exists : bool - Whether the path does indeed exist. - """ - raise NotImplementedError - - def is_hidden(self, path): - """Is path a hidden directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root dir). - - Returns - ------- - hidden : bool - Whether the path is hidden. - - """ - raise NotImplementedError - - def file_exists(self, path=""): - """Does a file exist at the given path? - - Like os.path.isfile - - Override this method in subclasses. - - Parameters - ---------- - path : string - The API path of a file to check for. - - Returns - ------- - exists : bool - Whether the file exists. - """ - raise NotImplementedError("must be implemented in a subclass") - - def exists(self, path): - """Does a file or directory exist at the given path? - - Like os.path.exists - - Parameters - ---------- - path : string - The API path of a file or directory to check for. - - Returns - ------- - exists : bool - Whether the target exists. - """ - return self.file_exists(path) or self.dir_exists(path) - - def get(self, path, content=True, type=None, format=None): - """Get a file or directory model.""" - raise NotImplementedError("must be implemented in a subclass") - - def save(self, model, path): - """ - Save a file or directory model to path. - - Should return the saved model with no content. Save implementations - should call self.run_pre_save_hook(model=model, path=path) prior to - writing any data. - """ - raise NotImplementedError("must be implemented in a subclass") - - def delete_file(self, path): - """Delete the file or directory at path.""" - raise NotImplementedError("must be implemented in a subclass") - - def rename_file(self, old_path, new_path): - """Rename a file or directory.""" - raise NotImplementedError("must be implemented in a subclass") - - # ContentsManager API part 2: methods that have useable default - # implementations, but can be overridden in subclasses. - - def delete(self, path): - """Delete a file/directory and any associated checkpoints.""" - path = path.strip("/") - if not path: - raise HTTPError(400, "Can't delete root") - self.delete_file(path) - self.checkpoints.delete_all_checkpoints(path) - - def rename(self, old_path, new_path): - """Rename a file and any checkpoints associated with that file.""" - self.rename_file(old_path, new_path) - self.checkpoints.rename_all_checkpoints(old_path, new_path) - - def update(self, model, path): - """Update the file's path - - For use in PATCH requests, to enable renaming a file without - re-uploading its contents. Only used for renaming at the moment. - """ - path = path.strip("/") - new_path = model.get("path", path).strip("/") - if path != new_path: - self.rename(path, new_path) - model = self.get(new_path, content=False) - return model - - def info_string(self): - return "Serving contents" - - def get_kernel_path(self, path, model=None): - """Return the API path for the kernel - - KernelManagers can turn this value into a filesystem path, - or ignore it altogether. - - The default value here will start kernels in the directory of the - notebook server. FileContentsManager overrides this to use the - directory containing the notebook. - """ - return "" - - def increment_filename(self, filename, path="", insert=""): - """Increment a filename until it is unique. - - Parameters - ---------- - filename : unicode - The name of a file, including extension - path : unicode - The API path of the target's directory - insert : unicode - The characters to insert after the base filename - - Returns - ------- - name : unicode - A filename that is unique, based on the input filename. - """ - # Extract the full suffix from the filename (e.g. .tar.gz) - path = path.strip("/") - basename, dot, ext = filename.rpartition(".") - if ext != "ipynb": - basename, dot, ext = filename.partition(".") - - suffix = dot + ext - - for i in itertools.count(): - if i: - insert_i = "{}{}".format(insert, i) - else: - insert_i = "" - name = "{basename}{insert}{suffix}".format( - basename=basename, insert=insert_i, suffix=suffix - ) - if not self.exists("{}/{}".format(path, name)): - break - return name - - def validate_notebook_model(self, model): - """Add failed-validation message to model""" - try: - validate_nb(model["content"]) - except ValidationError as e: - model["message"] = "Notebook validation failed: {}:\n{}".format( - e.message, - json.dumps(e.instance, indent=1, default=lambda obj: ""), - ) - return model - - def new_untitled(self, path="", type="", ext=""): - """Create a new untitled file or directory in path - - path must be a directory - - File extension can be specified. - - Use `new` to create files with a fully specified path (including filename). - """ - path = path.strip("/") - if not self.dir_exists(path): - raise HTTPError(404, "No such directory: %s" % path) - - model = {} - if type: - model["type"] = type - - if ext == ".ipynb": - model.setdefault("type", "notebook") - else: - model.setdefault("type", "file") - - insert = "" - if model["type"] == "directory": - untitled = self.untitled_directory - insert = " " - elif model["type"] == "notebook": - untitled = self.untitled_notebook - ext = ".ipynb" - elif model["type"] == "file": - untitled = self.untitled_file - else: - raise HTTPError(400, "Unexpected model type: %r" % model["type"]) - - name = self.increment_filename(untitled + ext, path, insert=insert) - path = "{0}/{1}".format(path, name) - return self.new(model, path) - - def new(self, model=None, path=""): - """Create a new file or directory and return its model with no content. - - To create a new untitled entity in a directory, use `new_untitled`. - """ - path = path.strip("/") - if model is None: - model = {} - - if path.endswith(".ipynb"): - model.setdefault("type", "notebook") - else: - model.setdefault("type", "file") - - # no content, not a directory, so fill out new-file model - if "content" not in model and model["type"] != "directory": - if model["type"] == "notebook": - model["content"] = new_notebook() - model["format"] = "json" - else: - model["content"] = "" - model["type"] = "file" - model["format"] = "text" - - model = self.save(model, path) - return model - - def copy(self, from_path, to_path=None): - """Copy an existing file and return its new model. - - If to_path not specified, it will be the parent directory of from_path. - If to_path is a directory, filename will increment `from_path-Copy#.ext`. - Considering multi-part extensions, the Copy# part will be placed before the first dot for all the extensions except `ipynb`. - For easier manual searching in case of notebooks, the Copy# part will be placed before the last dot. - - from_path must be a full path to a file. - """ - path = from_path.strip("/") - if to_path is not None: - to_path = to_path.strip("/") - - if "/" in path: - from_dir, from_name = path.rsplit("/", 1) - else: - from_dir = "" - from_name = path - - model = self.get(path) - model.pop("path", None) - model.pop("name", None) - if model["type"] == "directory": - raise HTTPError(400, "Can't copy directories") - - if to_path is None: - to_path = from_dir - if self.dir_exists(to_path): - name = copy_pat.sub(".", from_name) - to_name = self.increment_filename(name, to_path, insert="-Copy") - to_path = "{0}/{1}".format(to_path, to_name) - - model = self.save(model, to_path) - return model - - def log_info(self): - self.log.info(self.info_string()) - - def trust_notebook(self, path): - """Explicitly trust a notebook - - Parameters - ---------- - path : string - The path of a notebook - """ - model = self.get(path) - nb = model["content"] - self.log.warning("Trusting notebook %s", path) - self.notary.mark_cells(nb, True) - self.check_and_sign(nb, path) - - def check_and_sign(self, nb, path=""): - """Check for trusted cells, and sign the notebook. - - Called as a part of saving notebooks. - - Parameters - ---------- - nb : dict - The notebook dict - path : string - The notebook's path (for logging) - """ - if self.notary.check_cells(nb): - self.notary.sign(nb) - else: - self.log.warning("Notebook %s is not trusted", path) - - def mark_trusted_cells(self, nb, path=""): - """Mark cells as trusted if the notebook signature matches. - - Called as a part of loading notebooks. - - Parameters - ---------- - nb : dict - The notebook object (in current nbformat) - path : string - The notebook's path (for logging) - """ - trusted = self.notary.check_signature(nb) - if not trusted: - self.log.warning("Notebook %s is not trusted", path) - self.notary.mark_cells(nb, trusted) - - def should_list(self, name): - """Should this file/directory name be displayed in a listing?""" - return not any(fnmatch(name, glob) for glob in self.hide_globs) - - # Part 3: Checkpoints API - def create_checkpoint(self, path): - """Create a checkpoint.""" - return self.checkpoints.create_checkpoint(self, path) - - def restore_checkpoint(self, checkpoint_id, path): - """ - Restore a checkpoint. - """ - self.checkpoints.restore_checkpoint(self, checkpoint_id, path) - - def list_checkpoints(self, path): - return self.checkpoints.list_checkpoints(path) - - def delete_checkpoint(self, checkpoint_id, path): - return self.checkpoints.delete_checkpoint(checkpoint_id, path) - - -class AsyncContentsManager(ContentsManager): - """Base class for serving files and directories asynchronously.""" - - checkpoints_class = Type(AsyncCheckpoints, config=True) - checkpoints = Instance(AsyncCheckpoints, config=True) - checkpoints_kwargs = Dict(config=True) - - @default("checkpoints") - def _default_checkpoints(self): - return self.checkpoints_class(**self.checkpoints_kwargs) - - @default("checkpoints_kwargs") - def _default_checkpoints_kwargs(self): - return dict( - parent=self, - log=self.log, - ) - - # ContentsManager API part 1: methods that must be - # implemented in subclasses. - - async def dir_exists(self, path): - """Does a directory exist at the given path? - - Like os.path.isdir - - Override this method in subclasses. - - Parameters - ---------- - path : string - The path to check - - Returns - ------- - exists : bool - Whether the path does indeed exist. - """ - raise NotImplementedError - - async def is_hidden(self, path): - """Is path a hidden directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root dir). - - Returns - ------- - hidden : bool - Whether the path is hidden. - - """ - raise NotImplementedError - - async def file_exists(self, path=""): - """Does a file exist at the given path? - - Like os.path.isfile - - Override this method in subclasses. - - Parameters - ---------- - path : string - The API path of a file to check for. - - Returns - ------- - exists : bool - Whether the file exists. - """ - raise NotImplementedError("must be implemented in a subclass") - - async def exists(self, path): - """Does a file or directory exist at the given path? - - Like os.path.exists - - Parameters - ---------- - path : string - The API path of a file or directory to check for. - - Returns - ------- - exists : bool - Whether the target exists. - """ - return await ensure_async(self.file_exists(path)) or await ensure_async( - self.dir_exists(path) - ) - - async def get(self, path, content=True, type=None, format=None): - """Get a file or directory model.""" - raise NotImplementedError("must be implemented in a subclass") - - async def save(self, model, path): - """ - Save a file or directory model to path. - - Should return the saved model with no content. Save implementations - should call self.run_pre_save_hook(model=model, path=path) prior to - writing any data. - """ - raise NotImplementedError("must be implemented in a subclass") - - async def delete_file(self, path): - """Delete the file or directory at path.""" - raise NotImplementedError("must be implemented in a subclass") - - async def rename_file(self, old_path, new_path): - """Rename a file or directory.""" - raise NotImplementedError("must be implemented in a subclass") - - # ContentsManager API part 2: methods that have useable default - # implementations, but can be overridden in subclasses. - - async def delete(self, path): - """Delete a file/directory and any associated checkpoints.""" - path = path.strip("/") - if not path: - raise HTTPError(400, "Can't delete root") - - await self.delete_file(path) - await self.checkpoints.delete_all_checkpoints(path) - - async def rename(self, old_path, new_path): - """Rename a file and any checkpoints associated with that file.""" - await self.rename_file(old_path, new_path) - await self.checkpoints.rename_all_checkpoints(old_path, new_path) - - async def update(self, model, path): - """Update the file's path - - For use in PATCH requests, to enable renaming a file without - re-uploading its contents. Only used for renaming at the moment. - """ - path = path.strip("/") - new_path = model.get("path", path).strip("/") - if path != new_path: - await self.rename(path, new_path) - model = await self.get(new_path, content=False) - return model - - async def increment_filename(self, filename, path="", insert=""): - """Increment a filename until it is unique. - - Parameters - ---------- - filename : unicode - The name of a file, including extension - path : unicode - The API path of the target's directory - insert : unicode - The characters to insert after the base filename - - Returns - ------- - name : unicode - A filename that is unique, based on the input filename. - """ - # Extract the full suffix from the filename (e.g. .tar.gz) - path = path.strip("/") - basename, dot, ext = filename.rpartition(".") - if ext != "ipynb": - basename, dot, ext = filename.partition(".") - - suffix = dot + ext - - for i in itertools.count(): - if i: - insert_i = "{}{}".format(insert, i) - else: - insert_i = "" - name = "{basename}{insert}{suffix}".format( - basename=basename, insert=insert_i, suffix=suffix - ) - file_exists = await ensure_async(self.exists("{}/{}".format(path, name))) - if not file_exists: - break - return name - - async def new_untitled(self, path="", type="", ext=""): - """Create a new untitled file or directory in path - - path must be a directory - - File extension can be specified. - - Use `new` to create files with a fully specified path (including filename). - """ - path = path.strip("/") - dir_exists = await ensure_async(self.dir_exists(path)) - if not dir_exists: - raise HTTPError(404, "No such directory: %s" % path) - - model = {} - if type: - model["type"] = type - - if ext == ".ipynb": - model.setdefault("type", "notebook") - else: - model.setdefault("type", "file") - - insert = "" - if model["type"] == "directory": - untitled = self.untitled_directory - insert = " " - elif model["type"] == "notebook": - untitled = self.untitled_notebook - ext = ".ipynb" - elif model["type"] == "file": - untitled = self.untitled_file - else: - raise HTTPError(400, "Unexpected model type: %r" % model["type"]) - - name = await self.increment_filename(untitled + ext, path, insert=insert) - path = "{0}/{1}".format(path, name) - return await self.new(model, path) - - async def new(self, model=None, path=""): - """Create a new file or directory and return its model with no content. - - To create a new untitled entity in a directory, use `new_untitled`. - """ - path = path.strip("/") - if model is None: - model = {} - - if path.endswith(".ipynb"): - model.setdefault("type", "notebook") - else: - model.setdefault("type", "file") - - # no content, not a directory, so fill out new-file model - if "content" not in model and model["type"] != "directory": - if model["type"] == "notebook": - model["content"] = new_notebook() - model["format"] = "json" - else: - model["content"] = "" - model["type"] = "file" - model["format"] = "text" - - model = await self.save(model, path) - return model - - async def copy(self, from_path, to_path=None): - """Copy an existing file and return its new model. - - If to_path not specified, it will be the parent directory of from_path. - If to_path is a directory, filename will increment `from_path-Copy#.ext`. - Considering multi-part extensions, the Copy# part will be placed before the first dot for all the extensions except `ipynb`. - For easier manual searching in case of notebooks, the Copy# part will be placed before the last dot. - - from_path must be a full path to a file. - """ - path = from_path.strip("/") - if to_path is not None: - to_path = to_path.strip("/") - - if "/" in path: - from_dir, from_name = path.rsplit("/", 1) - else: - from_dir = "" - from_name = path - - model = await self.get(path) - model.pop("path", None) - model.pop("name", None) - if model["type"] == "directory": - raise HTTPError(400, "Can't copy directories") - if to_path is None: - to_path = from_dir - if await ensure_async(self.dir_exists(to_path)): - name = copy_pat.sub(".", from_name) - to_name = await self.increment_filename(name, to_path, insert="-Copy") - to_path = "{0}/{1}".format(to_path, to_name) - - model = await self.save(model, to_path) - return model - - async def trust_notebook(self, path): - """Explicitly trust a notebook - - Parameters - ---------- - path : string - The path of a notebook - """ - model = await self.get(path) - nb = model["content"] - self.log.warning("Trusting notebook %s", path) - self.notary.mark_cells(nb, True) - self.check_and_sign(nb, path) - - # Part 3: Checkpoints API - async def create_checkpoint(self, path): - """Create a checkpoint.""" - return await self.checkpoints.create_checkpoint(self, path) - - async def restore_checkpoint(self, checkpoint_id, path): - """ - Restore a checkpoint. - """ - await self.checkpoints.restore_checkpoint(self, checkpoint_id, path) - - async def list_checkpoints(self, path): - return await self.checkpoints.list_checkpoints(path) - - async def delete_checkpoint(self, checkpoint_id, path): - return await self.checkpoints.delete_checkpoint(checkpoint_id, path) diff --git a/server/jupyter_server/services/kernels/__init__.py b/server/jupyter_server/services/kernels/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/kernels/handlers.py b/server/jupyter_server/services/kernels/handlers.py deleted file mode 100644 index 84d14fd..0000000 --- a/server/jupyter_server/services/kernels/handlers.py +++ /dev/null @@ -1,785 +0,0 @@ -"""Tornado handlers for kernels. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#kernels-api -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -from textwrap import dedent -from traceback import format_tb - -from ipython_genutils.py3compat import cast_unicode -from jupyter_client import protocol_version as client_protocol_version - -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import date_default as json_default -from tornado import gen -from tornado import web -from tornado.concurrent import Future -from tornado.ioloop import IOLoop - -from ...base.handlers import APIHandler -from ...base.zmqhandlers import AuthenticatedZMQStreamHandler -from ...base.zmqhandlers import ( - deserialize_binary_message, - serialize_msg_to_ws_v1, - deserialize_msg_from_ws_v1, -) -from jupyter_server.utils import ensure_async -from jupyter_server.utils import url_escape -from jupyter_server.utils import url_path_join -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "kernels" - - -class KernelsAPIHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - -class MainKernelHandler(KernelsAPIHandler): - @web.authenticated - @authorized - async def get(self): - km = self.kernel_manager - kernels = await ensure_async(km.list_kernels()) - self.finish(json.dumps(kernels, default=json_default)) - - @web.authenticated - @authorized - async def post(self): - km = self.kernel_manager - model = self.get_json_body() - if model is None: - model = {"name": km.default_kernel_name} - else: - model.setdefault("name", km.default_kernel_name) - - kernel_id = await km.start_kernel(kernel_name=model["name"], path=model.get("path")) - model = await ensure_async(km.kernel_model(kernel_id)) - location = url_path_join(self.base_url, "api", "kernels", url_escape(kernel_id)) - self.set_header("Location", location) - self.set_status(201) - self.finish(json.dumps(model, default=json_default)) - - -class KernelHandler(KernelsAPIHandler): - @web.authenticated - @authorized - async def get(self, kernel_id): - km = self.kernel_manager - model = await ensure_async(km.kernel_model(kernel_id)) - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @authorized - async def delete(self, kernel_id): - km = self.kernel_manager - await ensure_async(km.shutdown_kernel(kernel_id)) - self.set_status(204) - self.finish() - - -class KernelActionHandler(KernelsAPIHandler): - @web.authenticated - @authorized - async def post(self, kernel_id, action): - km = self.kernel_manager - if action == "interrupt": - await ensure_async(km.interrupt_kernel(kernel_id)) - self.set_status(204) - if action == "restart": - - try: - await km.restart_kernel(kernel_id) - except Exception as e: - message = "Exception restarting kernel" - self.log.error(message, exc_info=True) - traceback = format_tb(e.__traceback__) - self.write(json.dumps(dict(message=message, traceback=traceback))) - self.set_status(500) - else: - model = await ensure_async(km.kernel_model(kernel_id)) - self.write(json.dumps(model, default=json_default)) - self.finish() - - -class ZMQChannelsHandler(AuthenticatedZMQStreamHandler): - """There is one ZMQChannelsHandler per running kernel and it oversees all - the sessions. - """ - - auth_resource = AUTH_RESOURCE - - # class-level registry of open sessions - # allows checking for conflict on session-id, - # which is used as a zmq identity and must be unique. - _open_sessions = {} - - @property - def kernel_info_timeout(self): - km_default = self.kernel_manager.kernel_info_timeout - return self.settings.get("kernel_info_timeout", km_default) - - @property - def limit_rate(self): - return self.settings.get("limit_rate", True) - - @property - def iopub_msg_rate_limit(self): - return self.settings.get("iopub_msg_rate_limit", 0) - - @property - def iopub_data_rate_limit(self): - return self.settings.get("iopub_data_rate_limit", 0) - - @property - def rate_limit_window(self): - return self.settings.get("rate_limit_window", 1.0) - - def __repr__(self): - return "%s(%s)" % ( - self.__class__.__name__, - getattr(self, "kernel_id", "uninitialized"), - ) - - def create_stream(self): - km = self.kernel_manager - identity = self.session.bsession - for channel in ("iopub", "shell", "control", "stdin"): - meth = getattr(km, "connect_" + channel) - self.channels[channel] = stream = meth(self.kernel_id, identity=identity) - stream.channel = channel - - def nudge(self): - """Nudge the zmq connections with kernel_info_requests - Returns a Future that will resolve when we have received - a shell or control reply and at least one iopub message, - ensuring that zmq subscriptions are established, - sockets are fully connected, and kernel is responsive. - Keeps retrying kernel_info_request until these are both received. - """ - kernel = self.kernel_manager.get_kernel(self.kernel_id) - - # Do not nudge busy kernels as kernel info requests sent to shell are - # queued behind execution requests. - # nudging in this case would cause a potentially very long wait - # before connections are opened, - # plus it is *very* unlikely that a busy kernel will not finish - # establishing its zmq subscriptions before processing the next request. - if getattr(kernel, "execution_state") == "busy": - self.log.debug("Nudge: not nudging busy kernel %s", self.kernel_id) - f = Future() - f.set_result(None) - return f - # Use a transient shell channel to prevent leaking - # shell responses to the front-end. - shell_channel = kernel.connect_shell() - # Use a transient control channel to prevent leaking - # control responses to the front-end. - control_channel = kernel.connect_control() - # The IOPub used by the client, whose subscriptions we are verifying. - iopub_channel = self.channels["iopub"] - - info_future = Future() - iopub_future = Future() - both_done = gen.multi([info_future, iopub_future]) - - def finish(_=None): - """Ensure all futures are resolved - which in turn triggers cleanup - """ - for f in (info_future, iopub_future): - if not f.done(): - f.set_result(None) - - def cleanup(_=None): - """Common cleanup""" - loop.remove_timeout(nudge_handle) - iopub_channel.stop_on_recv() - if not shell_channel.closed(): - shell_channel.close() - if not control_channel.closed(): - control_channel.close() - - # trigger cleanup when both message futures are resolved - both_done.add_done_callback(cleanup) - - def on_shell_reply(msg): - self.log.debug("Nudge: shell info reply received: %s", self.kernel_id) - if not info_future.done(): - self.log.debug("Nudge: resolving shell future: %s", self.kernel_id) - info_future.set_result(None) - - def on_control_reply(msg): - self.log.debug("Nudge: control info reply received: %s", self.kernel_id) - if not info_future.done(): - self.log.debug("Nudge: resolving control future: %s", self.kernel_id) - info_future.set_result(None) - - def on_iopub(msg): - self.log.debug("Nudge: IOPub received: %s", self.kernel_id) - if not iopub_future.done(): - iopub_channel.stop_on_recv() - self.log.debug("Nudge: resolving iopub future: %s", self.kernel_id) - iopub_future.set_result(None) - - iopub_channel.on_recv(on_iopub) - shell_channel.on_recv(on_shell_reply) - control_channel.on_recv(on_control_reply) - loop = IOLoop.current() - - # Nudge the kernel with kernel info requests until we get an IOPub message - def nudge(count): - count += 1 - - # NOTE: this close check appears to never be True during on_open, - # even when the peer has closed the connection - if self.ws_connection is None or self.ws_connection.is_closing(): - self.log.debug("Nudge: cancelling on closed websocket: %s", self.kernel_id) - finish() - return - - # check for stopped kernel - if self.kernel_id not in self.kernel_manager: - self.log.debug("Nudge: cancelling on stopped kernel: %s", self.kernel_id) - finish() - return - - # check for closed zmq socket - if shell_channel.closed(): - self.log.debug("Nudge: cancelling on closed zmq socket: %s", self.kernel_id) - finish() - return - - # check for closed zmq socket - if control_channel.closed(): - self.log.debug("Nudge: cancelling on closed zmq socket: %s", self.kernel_id) - finish() - return - - if not both_done.done(): - log = self.log.warning if count % 10 == 0 else self.log.debug - log("Nudge: attempt %s on kernel %s" % (count, self.kernel_id)) - self.session.send(shell_channel, "kernel_info_request") - self.session.send(control_channel, "kernel_info_request") - nonlocal nudge_handle - nudge_handle = loop.call_later(0.5, nudge, count) - - nudge_handle = loop.call_later(0, nudge, count=0) - - # resolve with a timeout if we get no response - future = gen.with_timeout(loop.time() + self.kernel_info_timeout, both_done) - # ensure we have no dangling resources or unresolved Futures in case of timeout - future.add_done_callback(finish) - return future - - def request_kernel_info(self): - """send a request for kernel_info""" - km = self.kernel_manager - kernel = km.get_kernel(self.kernel_id) - try: - # check for previous request - future = kernel._kernel_info_future - except AttributeError: - self.log.debug("Requesting kernel info from %s", self.kernel_id) - # Create a kernel_info channel to query the kernel protocol version. - # This channel will be closed after the kernel_info reply is received. - if self.kernel_info_channel is None: - self.kernel_info_channel = km.connect_shell(self.kernel_id) - self.kernel_info_channel.on_recv(self._handle_kernel_info_reply) - self.session.send(self.kernel_info_channel, "kernel_info_request") - # store the future on the kernel, so only one request is sent - kernel._kernel_info_future = self._kernel_info_future - else: - if not future.done(): - self.log.debug("Waiting for pending kernel_info request") - future.add_done_callback(lambda f: self._finish_kernel_info(f.result())) - return self._kernel_info_future - - def _handle_kernel_info_reply(self, msg): - """process the kernel_info_reply - - enabling msg spec adaptation, if necessary - """ - idents, msg = self.session.feed_identities(msg) - try: - msg = self.session.deserialize(msg) - except: - self.log.error("Bad kernel_info reply", exc_info=True) - self._kernel_info_future.set_result({}) - return - else: - info = msg["content"] - self.log.debug("Received kernel info: %s", info) - if msg["msg_type"] != "kernel_info_reply" or "protocol_version" not in info: - self.log.error("Kernel info request failed, assuming current %s", info) - info = {} - self._finish_kernel_info(info) - - # close the kernel_info channel, we don't need it anymore - if self.kernel_info_channel: - self.kernel_info_channel.close() - self.kernel_info_channel = None - - def _finish_kernel_info(self, info): - """Finish handling kernel_info reply - - Set up protocol adaptation, if needed, - and signal that connection can continue. - """ - protocol_version = info.get("protocol_version", client_protocol_version) - if protocol_version != client_protocol_version: - self.session.adapt_version = int(protocol_version.split(".")[0]) - self.log.info( - "Adapting from protocol version {protocol_version} (kernel {kernel_id}) to {client_protocol_version} (client).".format( - protocol_version=protocol_version, - kernel_id=self.kernel_id, - client_protocol_version=client_protocol_version, - ) - ) - if not self._kernel_info_future.done(): - self._kernel_info_future.set_result(info) - - def initialize(self): - super(ZMQChannelsHandler, self).initialize() - self.zmq_stream = None - self.channels = {} - self.kernel_id = None - self.kernel_info_channel = None - self._kernel_info_future = Future() - self._close_future = Future() - self.session_key = "" - - # Rate limiting code - self._iopub_window_msg_count = 0 - self._iopub_window_byte_count = 0 - self._iopub_msgs_exceeded = False - self._iopub_data_exceeded = False - # Queue of (time stamp, byte count) - # Allows you to specify that the byte count should be lowered - # by a delta amount at some point in the future. - self._iopub_window_byte_queue = [] - - async def pre_get(self): - # authenticate first - super(ZMQChannelsHandler, self).pre_get() - # check session collision: - await self._register_session() - # then request kernel info, waiting up to a certain time before giving up. - # We don't want to wait forever, because browsers don't take it well when - # servers never respond to websocket connection requests. - kernel = self.kernel_manager.get_kernel(self.kernel_id) - - if hasattr(kernel, "ready"): - try: - await kernel.ready - except Exception as e: - kernel.execution_state = "dead" - kernel.reason = str(e) - raise web.HTTPError(500, str(e)) from e - - self.session.key = kernel.session.key - future = self.request_kernel_info() - - def give_up(): - """Don't wait forever for the kernel to reply""" - if future.done(): - return - self.log.warning("Timeout waiting for kernel_info reply from %s", self.kernel_id) - future.set_result({}) - - loop = IOLoop.current() - loop.add_timeout(loop.time() + self.kernel_info_timeout, give_up) - # actually wait for it - await future - - async def get(self, kernel_id): - self.kernel_id = cast_unicode(kernel_id, "ascii") - await super(ZMQChannelsHandler, self).get(kernel_id=kernel_id) - - async def _register_session(self): - """Ensure we aren't creating a duplicate session. - - If a previous identical session is still open, close it to avoid collisions. - This is likely due to a client reconnecting from a lost network connection, - where the socket on our side has not been cleaned up yet. - """ - self.session_key = "%s:%s" % (self.kernel_id, self.session.session) - stale_handler = self._open_sessions.get(self.session_key) - if stale_handler: - self.log.warning("Replacing stale connection: %s", self.session_key) - await stale_handler.close() - if ( - self.kernel_id in self.kernel_manager - ): # only update open sessions if kernel is actively managed - self._open_sessions[self.session_key] = self - - def open(self, kernel_id): - super(ZMQChannelsHandler, self).open() - km = self.kernel_manager - km.notify_connect(kernel_id) - - # on new connections, flush the message buffer - buffer_info = km.get_buffer(kernel_id, self.session_key) - if buffer_info and buffer_info["session_key"] == self.session_key: - self.log.info("Restoring connection for %s", self.session_key) - if km.ports_changed(kernel_id): - # If the kernel's ports have changed (some restarts trigger this) - # then reset the channels so nudge() is using the correct iopub channel - self.create_stream() - else: - # The kernel's ports have not changed; use the channels captured in the buffer - self.channels = buffer_info["channels"] - - connected = self.nudge() - - def replay(value): - replay_buffer = buffer_info["buffer"] - if replay_buffer: - self.log.info("Replaying %s buffered messages", len(replay_buffer)) - for channel, msg_list in replay_buffer: - stream = self.channels[channel] - self._on_zmq_reply(stream, msg_list) - - connected.add_done_callback(replay) - else: - try: - self.create_stream() - connected = self.nudge() - except web.HTTPError as e: - # Do not log error if the kernel is already shutdown, - # as it's normal that it's not responding - try: - self.kernel_manager.get_kernel(kernel_id) - - self.log.error("Error opening stream: %s", e) - except KeyError: - pass - # WebSockets don't respond to traditional error codes so we - # close the connection. - for channel, stream in self.channels.items(): - if not stream.closed(): - stream.close() - self.close() - return - - km.add_restart_callback(self.kernel_id, self.on_kernel_restarted) - km.add_restart_callback(self.kernel_id, self.on_restart_failed, "dead") - - def subscribe(value): - for channel, stream in self.channels.items(): - stream.on_recv_stream(self._on_zmq_reply) - - connected.add_done_callback(subscribe) - - return connected - - def on_message(self, ws_msg): - if not self.channels: - # already closed, ignore the message - self.log.debug("Received message on closed websocket %r", ws_msg) - return - - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - channel, msg_list = deserialize_msg_from_ws_v1(ws_msg) - msg = { - "header": None, - } - else: - if isinstance(ws_msg, bytes): - msg = deserialize_binary_message(ws_msg) - else: - msg = json.loads(ws_msg) - msg_list = [] - channel = msg.pop("channel", None) - - if channel is None: - self.log.warning("No channel specified, assuming shell: %s", msg) - channel = "shell" - if channel not in self.channels: - self.log.warning("No such channel: %r", channel) - return - am = self.kernel_manager.allowed_message_types - ignore_msg = False - if am: - msg["header"] = self.get_part("header", msg["header"], msg_list) - if msg["header"]["msg_type"] not in am: - self.log.warning( - 'Received message of type "%s", which is not allowed. Ignoring.' - % msg["header"]["msg_type"] - ) - ignore_msg = True - if not ignore_msg: - stream = self.channels[channel] - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - self.session.send_raw(stream, msg_list) - else: - self.session.send(stream, msg) - - def get_part(self, field, value, msg_list): - if value is None: - field2idx = { - "header": 0, - "parent_header": 1, - "content": 3, - } - value = self.session.unpack(msg_list[field2idx[field]]) - return value - - def _on_zmq_reply(self, stream, msg_list): - idents, fed_msg_list = self.session.feed_identities(msg_list) - - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - msg = {"header": None, "parent_header": None, "content": None} - else: - msg = self.session.deserialize(fed_msg_list) - - channel = getattr(stream, "channel", None) - parts = fed_msg_list[1:] - - self._on_error(channel, msg, parts) - - if self._limit_rate(channel, msg, parts): - return - - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - super(ZMQChannelsHandler, self)._on_zmq_reply(stream, parts) - else: - super(ZMQChannelsHandler, self)._on_zmq_reply(stream, msg) - - def write_stderr(self, error_message, parent_header): - self.log.warning(error_message) - err_msg = self.session.msg( - "stream", - content={"text": error_message + "\n", "name": "stderr"}, - parent=parent_header, - ) - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - bin_msg = serialize_msg_to_ws_v1(err_msg, "iopub", self.session.pack) - self.write_message(bin_msg, binary=True) - else: - err_msg["channel"] = "iopub" - self.write_message(json.dumps(err_msg, default=json_default)) - - def _limit_rate(self, channel, msg, msg_list): - if not (self.limit_rate and channel == "iopub"): - return False - - msg["header"] = self.get_part("header", msg["header"], msg_list) - - msg_type = msg["header"]["msg_type"] - if msg_type == "status": - msg["content"] = self.get_part("content", msg["content"], msg_list) - if msg["content"].get("execution_state") == "idle": - # reset rate limit counter on status=idle, - # to avoid 'Run All' hitting limits prematurely. - self._iopub_window_byte_queue = [] - self._iopub_window_msg_count = 0 - self._iopub_window_byte_count = 0 - self._iopub_msgs_exceeded = False - self._iopub_data_exceeded = False - - if msg_type not in {"status", "comm_open", "execute_input"}: - # Remove the counts queued for removal. - now = IOLoop.current().time() - while len(self._iopub_window_byte_queue) > 0: - queued = self._iopub_window_byte_queue[0] - if now >= queued[0]: - self._iopub_window_byte_count -= queued[1] - self._iopub_window_msg_count -= 1 - del self._iopub_window_byte_queue[0] - else: - # This part of the queue hasn't be reached yet, so we can - # abort the loop. - break - - # Increment the bytes and message count - self._iopub_window_msg_count += 1 - if msg_type == "stream": - byte_count = sum([len(x) for x in msg_list]) - else: - byte_count = 0 - self._iopub_window_byte_count += byte_count - - # Queue a removal of the byte and message count for a time in the - # future, when we are no longer interested in it. - self._iopub_window_byte_queue.append((now + self.rate_limit_window, byte_count)) - - # Check the limits, set the limit flags, and reset the - # message and data counts. - msg_rate = float(self._iopub_window_msg_count) / self.rate_limit_window - data_rate = float(self._iopub_window_byte_count) / self.rate_limit_window - - # Check the msg rate - if self.iopub_msg_rate_limit > 0 and msg_rate > self.iopub_msg_rate_limit: - if not self._iopub_msgs_exceeded: - self._iopub_msgs_exceeded = True - msg["parent_header"] = self.get_part( - "parent_header", msg["parent_header"], msg_list - ) - self.write_stderr( - dedent( - """\ - IOPub message rate exceeded. - The Jupyter server will temporarily stop sending output - to the client in order to avoid crashing it. - To change this limit, set the config variable - `--ServerApp.iopub_msg_rate_limit`. - - Current values: - ServerApp.iopub_msg_rate_limit={} (msgs/sec) - ServerApp.rate_limit_window={} (secs) - """.format( - self.iopub_msg_rate_limit, self.rate_limit_window - ) - ), - msg["parent_header"], - ) - else: - # resume once we've got some headroom below the limit - if self._iopub_msgs_exceeded and msg_rate < (0.8 * self.iopub_msg_rate_limit): - self._iopub_msgs_exceeded = False - if not self._iopub_data_exceeded: - self.log.warning("iopub messages resumed") - - # Check the data rate - if self.iopub_data_rate_limit > 0 and data_rate > self.iopub_data_rate_limit: - if not self._iopub_data_exceeded: - self._iopub_data_exceeded = True - msg["parent_header"] = self.get_part( - "parent_header", msg["parent_header"], msg_list - ) - self.write_stderr( - dedent( - """\ - IOPub data rate exceeded. - The Jupyter server will temporarily stop sending output - to the client in order to avoid crashing it. - To change this limit, set the config variable - `--ServerApp.iopub_data_rate_limit`. - - Current values: - ServerApp.iopub_data_rate_limit={} (bytes/sec) - ServerApp.rate_limit_window={} (secs) - """.format( - self.iopub_data_rate_limit, self.rate_limit_window - ) - ), - msg["parent_header"], - ) - else: - # resume once we've got some headroom below the limit - if self._iopub_data_exceeded and data_rate < (0.8 * self.iopub_data_rate_limit): - self._iopub_data_exceeded = False - if not self._iopub_msgs_exceeded: - self.log.warning("iopub messages resumed") - - # If either of the limit flags are set, do not send the message. - if self._iopub_msgs_exceeded or self._iopub_data_exceeded: - # we didn't send it, remove the current message from the calculus - self._iopub_window_msg_count -= 1 - self._iopub_window_byte_count -= byte_count - self._iopub_window_byte_queue.pop(-1) - return True - - return False - - def close(self): - super(ZMQChannelsHandler, self).close() - return self._close_future - - def on_close(self): - self.log.debug("Websocket closed %s", self.session_key) - # unregister myself as an open session (only if it's really me) - if self._open_sessions.get(self.session_key) is self: - self._open_sessions.pop(self.session_key) - - km = self.kernel_manager - if self.kernel_id in km: - km.notify_disconnect(self.kernel_id) - km.remove_restart_callback( - self.kernel_id, - self.on_kernel_restarted, - ) - km.remove_restart_callback( - self.kernel_id, - self.on_restart_failed, - "dead", - ) - - # start buffering instead of closing if this was the last connection - if km._kernel_connections[self.kernel_id] == 0: - km.start_buffering(self.kernel_id, self.session_key, self.channels) - self._close_future.set_result(None) - return - - # This method can be called twice, once by self.kernel_died and once - # from the WebSocket close event. If the WebSocket connection is - # closed before the ZMQ streams are setup, they could be None. - for channel, stream in self.channels.items(): - if stream is not None and not stream.closed(): - stream.on_recv(None) - stream.close() - - self.channels = {} - self._close_future.set_result(None) - - def _send_status_message(self, status): - iopub = self.channels.get("iopub", None) - if iopub and not iopub.closed(): - # flush IOPub before sending a restarting/dead status message - # ensures proper ordering on the IOPub channel - # that all messages from the stopped kernel have been delivered - iopub.flush() - msg = self.session.msg("status", {"execution_state": status}) - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - bin_msg = serialize_msg_to_ws_v1(msg, "iopub", self.session.pack) - self.write_message(bin_msg, binary=True) - else: - msg["channel"] = "iopub" - self.write_message(json.dumps(msg, default=json_default)) - - def on_kernel_restarted(self): - self.log.warning("kernel %s restarted", self.kernel_id) - self._send_status_message("restarting") - - def on_restart_failed(self): - self.log.error("kernel %s restarted failed!", self.kernel_id) - self._send_status_message("dead") - - def _on_error(self, channel, msg, msg_list): - if self.kernel_manager.allow_tracebacks: - return - - if channel == "iopub": - msg["header"] = self.get_part("header", msg["header"], msg_list) - if msg["header"]["msg_type"] == "error": - msg["content"] = self.get_part("content", msg["content"], msg_list) - msg["content"]["ename"] = "ExecutionError" - msg["content"]["evalue"] = "Execution error" - msg["content"]["traceback"] = [self.kernel_manager.traceback_replacement_message] - if self.selected_subprotocol == "v1.kernel.websocket.jupyter.org": - msg_list[3] = self.session.pack(msg["content"]) - - -# ----------------------------------------------------------------------------- -# URL to handler mappings -# ----------------------------------------------------------------------------- - - -_kernel_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" -_kernel_action_regex = r"(?Prestart|interrupt)" - -default_handlers = [ - (r"/api/kernels", MainKernelHandler), - (r"/api/kernels/%s" % _kernel_id_regex, KernelHandler), - ( - r"/api/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), - KernelActionHandler, - ), - (r"/api/kernels/%s/channels" % _kernel_id_regex, ZMQChannelsHandler), -] diff --git a/server/jupyter_server/services/kernels/kernelmanager.py b/server/jupyter_server/services/kernels/kernelmanager.py deleted file mode 100644 index 8f8fff7..0000000 --- a/server/jupyter_server/services/kernels/kernelmanager.py +++ /dev/null @@ -1,659 +0,0 @@ -"""A MultiKernelManager for use in the Jupyter server - -- raises HTTPErrors -- creates REST API models -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import asyncio -import os -from collections import defaultdict -from datetime import datetime -from datetime import timedelta -from functools import partial - -from jupyter_client.multikernelmanager import AsyncMultiKernelManager -from jupyter_client.multikernelmanager import MultiKernelManager -from jupyter_client.session import Session -from jupyter_core.paths import exists -from tornado import web -from tornado.concurrent import Future -from tornado.ioloop import IOLoop -from tornado.ioloop import PeriodicCallback -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import Float -from traitlets import Instance -from traitlets import Integer -from traitlets import List -from traitlets import TraitError -from traitlets import Unicode -from traitlets import validate - -from jupyter_server._tz import isoformat -from jupyter_server._tz import utcnow -from jupyter_server.prometheus.metrics import KERNEL_CURRENTLY_RUNNING_TOTAL -from jupyter_server.utils import ensure_async -from jupyter_server.utils import to_os_path - - -class MappingKernelManager(MultiKernelManager): - """A KernelManager that handles - - File mapping - - HTTP error handling - - Kernel message filtering - """ - - @default("kernel_manager_class") - def _default_kernel_manager_class(self): - return "jupyter_client.ioloop.IOLoopKernelManager" - - kernel_argv = List(Unicode()) - - root_dir = Unicode(config=True) - - _kernel_connections = Dict() - - _kernel_ports = Dict() - - _culler_callback = None - - _initialized_culler = False - - @default("root_dir") - def _default_root_dir(self): - try: - return self.parent.root_dir - except AttributeError: - return os.getcwd() - - @validate("root_dir") - def _update_root_dir(self, proposal): - """Do a bit of validation of the root dir.""" - value = proposal["value"] - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - if not exists(value) or not os.path.isdir(value): - raise TraitError("kernel root dir %r is not a directory" % value) - return value - - cull_idle_timeout = Integer( - 0, - config=True, - help="""Timeout (in seconds) after which a kernel is considered idle and ready to be culled. - Values of 0 or lower disable culling. Very short timeouts may result in kernels being culled - for users with poor network connections.""", - ) - - cull_interval_default = 300 # 5 minutes - cull_interval = Integer( - cull_interval_default, - config=True, - help="""The interval (in seconds) on which to check for idle kernels exceeding the cull timeout value.""", - ) - - cull_connected = Bool( - False, - config=True, - help="""Whether to consider culling kernels which have one or more connections. - Only effective if cull_idle_timeout > 0.""", - ) - - cull_busy = Bool( - False, - config=True, - help="""Whether to consider culling kernels which are busy. - Only effective if cull_idle_timeout > 0.""", - ) - - buffer_offline_messages = Bool( - True, - config=True, - help="""Whether messages from kernels whose frontends have disconnected should be buffered in-memory. - - When True (default), messages are buffered and replayed on reconnect, - avoiding lost messages due to interrupted connectivity. - - Disable if long-running kernels will produce too much output while - no frontends are connected. - """, - ) - - kernel_info_timeout = Float( - 60, - config=True, - help="""Timeout for giving up on a kernel (in seconds). - - On starting and restarting kernels, we check whether the - kernel is running and responsive by sending kernel_info_requests. - This sets the timeout in seconds for how long the kernel can take - before being presumed dead. - This affects the MappingKernelManager (which handles kernel restarts) - and the ZMQChannelsHandler (which handles the startup). - """, - ) - - _kernel_buffers = Any() - - @default("_kernel_buffers") - def _default_kernel_buffers(self): - return defaultdict(lambda: {"buffer": [], "session_key": "", "channels": {}}) - - last_kernel_activity = Instance( - datetime, - help="The last activity on any kernel, including shutting down a kernel", - ) - - def __init__(self, **kwargs): - self.pinned_superclass = MultiKernelManager - self.pinned_superclass.__init__(self, **kwargs) - self.last_kernel_activity = utcnow() - - allowed_message_types = List( - trait=Unicode(), - config=True, - help="""White list of allowed kernel message types. - When the list is empty, all message types are allowed. - """, - ) - - allow_tracebacks = Bool( - True, config=True, help=("Whether to send tracebacks to clients on exceptions.") - ) - - traceback_replacement_message = Unicode( - "An exception occurred at runtime, which is not shown due to security reasons.", - config=True, - help=("Message to print when allow_tracebacks is False, and an exception occurs"), - ) - - # ------------------------------------------------------------------------- - # Methods for managing kernels and sessions - # ------------------------------------------------------------------------- - - def _handle_kernel_died(self, kernel_id): - """notice that a kernel died""" - self.log.warning("Kernel %s died, removing from map.", kernel_id) - self.remove_kernel(kernel_id) - - def cwd_for_path(self, path): - """Turn API path into absolute OS path.""" - os_path = to_os_path(path, self.root_dir) - # in the case of documents and kernels not being on the same filesystem, - # walk up to root_dir if the paths don't exist - while not os.path.isdir(os_path) and os_path != self.root_dir: - os_path = os.path.dirname(os_path) - return os_path - - async def start_kernel(self, kernel_id=None, path=None, **kwargs): - """Start a kernel for a session and return its kernel_id. - - Parameters - ---------- - kernel_id : uuid - The uuid to associate the new kernel with. If this - is not None, this kernel will be persistent whenever it is - requested. - path : API path - The API path (unicode, '/' delimited) for the cwd. - Will be transformed to an OS path relative to root_dir. - kernel_name : str - The name identifying which kernel spec to launch. This is ignored if - an existing kernel is returned, but it may be checked in the future. - """ - if kernel_id is None or kernel_id not in self: - if path is not None: - kwargs["cwd"] = self.cwd_for_path(path) - if kernel_id is not None: - kwargs["kernel_id"] = kernel_id - kernel_id = await ensure_async(self.pinned_superclass.start_kernel(self, **kwargs)) - self._kernel_connections[kernel_id] = 0 - fut = asyncio.ensure_future(self._finish_kernel_start(kernel_id)) - if not getattr(self, "use_pending_kernels", None): - await fut - # add busy/activity markers: - kernel = self.get_kernel(kernel_id) - kernel.execution_state = "starting" - kernel.reason = "" - kernel.last_activity = utcnow() - self.log.info("Kernel started: %s" % kernel_id) - self.log.debug("Kernel args: %r" % kwargs) - - # Increase the metric of number of kernels running - # for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels(type=self._kernels[kernel_id].kernel_name).inc() - - else: - self.log.info("Using existing kernel: %s" % kernel_id) - - # Initialize culling if not already - if not self._initialized_culler: - self.initialize_culler() - - return kernel_id - - async def _finish_kernel_start(self, kernel_id): - km = self.get_kernel(kernel_id) - if hasattr(km, "ready"): - try: - await km.ready - except Exception: - self.log.exception(km.ready.exception()) - return - - self._kernel_ports[kernel_id] = km.ports - self.start_watching_activity(kernel_id) - # register callback for failed auto-restart - self.add_restart_callback( - kernel_id, - lambda: self._handle_kernel_died(kernel_id), - "dead", - ) - - def ports_changed(self, kernel_id): - """Used by ZMQChannelsHandler to determine how to coordinate nudge and replays. - - Ports are captured when starting a kernel (via MappingKernelManager). Ports - are considered changed (following restarts) if the referenced KernelManager - is using a set of ports different from those captured at startup. If changes - are detected, the captured set is updated and a value of True is returned. - - NOTE: Use is exclusive to ZMQChannelsHandler because this object is a singleton - instance while ZMQChannelsHandler instances are per WebSocket connection that - can vary per kernel lifetime. - """ - changed_ports = self._get_changed_ports(kernel_id) - if changed_ports: - # If changed, update captured ports and return True, else return False. - self.log.debug(f"Port change detected for kernel: {kernel_id}") - self._kernel_ports[kernel_id] = changed_ports - return True - return False - - def _get_changed_ports(self, kernel_id): - """Internal method to test if a kernel's ports have changed and, if so, return their values. - - This method does NOT update the captured ports for the kernel as that can only be done - by ZMQChannelsHandler, but instead returns the new list of ports if they are different - than those captured at startup. This enables the ability to conditionally restart - activity monitoring immediately following a kernel's restart (if ports have changed). - """ - # Get current ports and return comparison with ports captured at startup. - km = self.get_kernel(kernel_id) - if km.ports != self._kernel_ports[kernel_id]: - return km.ports - return None - - def start_buffering(self, kernel_id, session_key, channels): - """Start buffering messages for a kernel - - Parameters - ---------- - kernel_id : str - The id of the kernel to stop buffering. - session_key : str - The session_key, if any, that should get the buffer. - If the session_key matches the current buffered session_key, - the buffer will be returned. - channels : dict({'channel': ZMQStream}) - The zmq channels whose messages should be buffered. - """ - - if not self.buffer_offline_messages: - for channel, stream in channels.items(): - stream.close() - return - - self.log.info("Starting buffering for %s", session_key) - self._check_kernel_id(kernel_id) - # clear previous buffering state - self.stop_buffering(kernel_id) - buffer_info = self._kernel_buffers[kernel_id] - # record the session key because only one session can buffer - buffer_info["session_key"] = session_key - # TODO: the buffer should likely be a memory bounded queue, we're starting with a list to keep it simple - buffer_info["buffer"] = [] - buffer_info["channels"] = channels - - # forward any future messages to the internal buffer - def buffer_msg(channel, msg_parts): - self.log.debug("Buffering msg on %s:%s", kernel_id, channel) - buffer_info["buffer"].append((channel, msg_parts)) - - for channel, stream in channels.items(): - stream.on_recv(partial(buffer_msg, channel)) - - def get_buffer(self, kernel_id, session_key): - """Get the buffer for a given kernel - - Parameters - ---------- - kernel_id : str - The id of the kernel to stop buffering. - session_key : str, optional - The session_key, if any, that should get the buffer. - If the session_key matches the current buffered session_key, - the buffer will be returned. - """ - self.log.debug("Getting buffer for %s", kernel_id) - if kernel_id not in self._kernel_buffers: - return - - buffer_info = self._kernel_buffers[kernel_id] - if buffer_info["session_key"] == session_key: - # remove buffer - self._kernel_buffers.pop(kernel_id) - # only return buffer_info if it's a match - return buffer_info - else: - self.stop_buffering(kernel_id) - - def stop_buffering(self, kernel_id): - """Stop buffering kernel messages - - Parameters - ---------- - kernel_id : str - The id of the kernel to stop buffering. - """ - self.log.debug("Clearing buffer for %s", kernel_id) - self._check_kernel_id(kernel_id) - - if kernel_id not in self._kernel_buffers: - return - buffer_info = self._kernel_buffers.pop(kernel_id) - # close buffering streams - for stream in buffer_info["channels"].values(): - if not stream.closed(): - stream.on_recv(None) - stream.close() - - msg_buffer = buffer_info["buffer"] - if msg_buffer: - self.log.info( - "Discarding %s buffered messages for %s", - len(msg_buffer), - buffer_info["session_key"], - ) - - def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - self.stop_watching_activity(kernel_id) - self.stop_buffering(kernel_id) - self._kernel_connections.pop(kernel_id, None) - - # Decrease the metric of number of kernels - # running for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels(type=self._kernels[kernel_id].kernel_name).dec() - - self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart) - # Unlike its async sibling method in AsyncMappingKernelManager, removing the kernel_id - # from the connections dictionary isn't as problematic before the shutdown since the - # method is synchronous. However, we'll keep the relative call orders the same from - # a maintenance perspective. - self._kernel_connections.pop(kernel_id, None) - self._kernel_ports.pop(kernel_id, None) - - async def restart_kernel(self, kernel_id, now=False): - """Restart a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - await ensure_async(self.pinned_superclass.restart_kernel(self, kernel_id, now=now)) - kernel = self.get_kernel(kernel_id) - # return a Future that will resolve when the kernel has successfully restarted - channel = kernel.connect_shell() - future = Future() - - def finish(): - """Common cleanup when restart finishes/fails for any reason.""" - if not channel.closed(): - channel.close() - loop.remove_timeout(timeout) - kernel.remove_restart_callback(on_restart_failed, "dead") - - def on_reply(msg): - self.log.debug("Kernel info reply received: %s", kernel_id) - finish() - if not future.done(): - future.set_result(msg) - - def on_timeout(): - self.log.warning("Timeout waiting for kernel_info_reply: %s", kernel_id) - finish() - if not future.done(): - future.set_exception(TimeoutError("Timeout waiting for restart")) - - def on_restart_failed(): - self.log.warning("Restarting kernel failed: %s", kernel_id) - finish() - if not future.done(): - future.set_exception(RuntimeError("Restart failed")) - - kernel.add_restart_callback(on_restart_failed, "dead") - kernel.session.send(channel, "kernel_info_request") - channel.on_recv(on_reply) - loop = IOLoop.current() - timeout = loop.add_timeout(loop.time() + self.kernel_info_timeout, on_timeout) - # Re-establish activity watching if ports have changed... - if self._get_changed_ports(kernel_id) is not None: - self.stop_watching_activity(kernel_id) - self.start_watching_activity(kernel_id) - return future - - def notify_connect(self, kernel_id): - """Notice a new connection to a kernel""" - if kernel_id in self._kernel_connections: - self._kernel_connections[kernel_id] += 1 - - def notify_disconnect(self, kernel_id): - """Notice a disconnection from a kernel""" - if kernel_id in self._kernel_connections: - self._kernel_connections[kernel_id] -= 1 - - def kernel_model(self, kernel_id): - """Return a JSON-safe dict representing a kernel - - For use in representing kernels in the JSON APIs. - """ - self._check_kernel_id(kernel_id) - kernel = self._kernels[kernel_id] - - model = { - "id": kernel_id, - "name": kernel.kernel_name, - "last_activity": isoformat(kernel.last_activity), - "execution_state": kernel.execution_state, - "connections": self._kernel_connections.get(kernel_id, 0), - } - if getattr(kernel, "reason", None): - model["reason"] = kernel.reason - return model - - def list_kernels(self): - """Returns a list of kernel_id's of kernels running.""" - kernels = [] - kernel_ids = self.pinned_superclass.list_kernel_ids(self) - for kernel_id in kernel_ids: - try: - model = self.kernel_model(kernel_id) - kernels.append(model) - except (web.HTTPError, KeyError): - pass # Probably due to a (now) non-existent kernel, continue building the list - return kernels - - # override _check_kernel_id to raise 404 instead of KeyError - def _check_kernel_id(self, kernel_id): - """Check a that a kernel_id exists and raise 404 if not.""" - if kernel_id not in self: - raise web.HTTPError(404, "Kernel does not exist: %s" % kernel_id) - - # monitoring activity: - - def start_watching_activity(self, kernel_id): - """Start watching IOPub messages on a kernel for activity. - - - update last_activity on every message - - record execution_state from status messages - """ - kernel = self._kernels[kernel_id] - # add busy/activity markers: - kernel.execution_state = "starting" - kernel.reason = "" - kernel.last_activity = utcnow() - kernel._activity_stream = kernel.connect_iopub() - session = Session( - config=kernel.session.config, - key=kernel.session.key, - ) - - def record_activity(msg_list): - """Record an IOPub message arriving from a kernel""" - self.last_kernel_activity = kernel.last_activity = utcnow() - - idents, fed_msg_list = session.feed_identities(msg_list) - msg = session.deserialize(fed_msg_list) - - msg_type = msg["header"]["msg_type"] - if msg_type == "status": - kernel.execution_state = msg["content"]["execution_state"] - self.log.debug( - "activity on %s: %s (%s)", - kernel_id, - msg_type, - kernel.execution_state, - ) - else: - self.log.debug("activity on %s: %s", kernel_id, msg_type) - - kernel._activity_stream.on_recv(record_activity) - - def stop_watching_activity(self, kernel_id): - """Stop watching IOPub messages on a kernel for activity.""" - kernel = self._kernels[kernel_id] - if getattr(kernel, "_activity_stream", None): - kernel._activity_stream.close() - kernel._activity_stream = None - - def initialize_culler(self): - """Start idle culler if 'cull_idle_timeout' is greater than zero. - - Regardless of that value, set flag that we've been here. - """ - if not self._initialized_culler and self.cull_idle_timeout > 0: - if self._culler_callback is None: - loop = IOLoop.current() - if self.cull_interval <= 0: # handle case where user set invalid value - self.log.warning( - "Invalid value for 'cull_interval' detected (%s) - using default value (%s).", - self.cull_interval, - self.cull_interval_default, - ) - self.cull_interval = self.cull_interval_default - self._culler_callback = PeriodicCallback( - self.cull_kernels, 1000 * self.cull_interval - ) - self.log.info( - "Culling kernels with idle durations > %s seconds at %s second intervals ...", - self.cull_idle_timeout, - self.cull_interval, - ) - if self.cull_busy: - self.log.info("Culling kernels even if busy") - if self.cull_connected: - self.log.info("Culling kernels even with connected clients") - self._culler_callback.start() - - self._initialized_culler = True - - async def cull_kernels(self): - self.log.debug( - "Polling every %s seconds for kernels idle > %s seconds...", - self.cull_interval, - self.cull_idle_timeout, - ) - """Create a separate list of kernels to avoid conflicting updates while iterating""" - for kernel_id in list(self._kernels): - try: - await self.cull_kernel_if_idle(kernel_id) - except Exception as e: - self.log.exception( - "The following exception was encountered while checking the idle duration of kernel %s: %s", - kernel_id, - e, - ) - - async def cull_kernel_if_idle(self, kernel_id): - kernel = self._kernels[kernel_id] - - if getattr(kernel, "execution_state") == "dead": - self.log.warning( - "Culling '%s' dead kernel '%s' (%s).", - kernel.execution_state, - kernel.kernel_name, - kernel_id, - ) - await ensure_async(self.shutdown_kernel(kernel_id)) - return - - if hasattr( - kernel, "last_activity" - ): # last_activity is monkey-patched, so ensure that has occurred - self.log.debug( - "kernel_id=%s, kernel_name=%s, last_activity=%s", - kernel_id, - kernel.kernel_name, - kernel.last_activity, - ) - dt_now = utcnow() - dt_idle = dt_now - kernel.last_activity - # Compute idle properties - is_idle_time = dt_idle > timedelta(seconds=self.cull_idle_timeout) - is_idle_execute = self.cull_busy or (kernel.execution_state != "busy") - connections = self._kernel_connections.get(kernel_id, 0) - is_idle_connected = self.cull_connected or not connections - # Cull the kernel if all three criteria are met - if is_idle_time and is_idle_execute and is_idle_connected: - idle_duration = int(dt_idle.total_seconds()) - self.log.warning( - "Culling '%s' kernel '%s' (%s) with %d connections due to %s seconds of inactivity.", - kernel.execution_state, - kernel.kernel_name, - kernel_id, - connections, - idle_duration, - ) - await ensure_async(self.shutdown_kernel(kernel_id)) - - -# AsyncMappingKernelManager inherits as much as possible from MappingKernelManager, -# overriding only what is different. -class AsyncMappingKernelManager(MappingKernelManager, AsyncMultiKernelManager): - @default("kernel_manager_class") - def _default_kernel_manager_class(self): - return "jupyter_client.ioloop.AsyncIOLoopKernelManager" - - def __init__(self, **kwargs): - self.pinned_superclass = AsyncMultiKernelManager - self.pinned_superclass.__init__(self, **kwargs) - self.last_kernel_activity = utcnow() - - async def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - self.stop_watching_activity(kernel_id) - self.stop_buffering(kernel_id) - - # Decrease the metric of number of kernels - # running for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels(type=self._kernels[kernel_id].kernel_name).dec() - - # Finish shutting down the kernel before clearing state to avoid a race condition. - ret = await self.pinned_superclass.shutdown_kernel( - self, kernel_id, now=now, restart=restart - ) - self._kernel_connections.pop(kernel_id, None) - self._kernel_ports.pop(kernel_id, None) - return ret diff --git a/server/jupyter_server/services/kernelspecs/__init__.py b/server/jupyter_server/services/kernelspecs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/kernelspecs/handlers.py b/server/jupyter_server/services/kernelspecs/handlers.py deleted file mode 100644 index 89bb4e4..0000000 --- a/server/jupyter_server/services/kernelspecs/handlers.py +++ /dev/null @@ -1,109 +0,0 @@ -"""Tornado handlers for kernel specifications. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-25%3A-Registry-of-installed-kernels#rest-api -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import glob -import json -import os - -pjoin = os.path.join - -from tornado import web - -from ...base.handlers import APIHandler -from ...utils import ensure_async, url_path_join, url_unescape -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "kernelspecs" - - -def kernelspec_model(handler, name, spec_dict, resource_dir): - """Load a KernelSpec by name and return the REST API model""" - d = {"name": name, "spec": spec_dict, "resources": {}} - - # Add resource files if they exist - resource_dir = resource_dir - for resource in ["kernel.js", "kernel.css"]: - if os.path.exists(pjoin(resource_dir, resource)): - d["resources"][resource] = url_path_join( - handler.base_url, "kernelspecs", name, resource - ) - for logo_file in glob.glob(pjoin(resource_dir, "logo-*")): - fname = os.path.basename(logo_file) - no_ext, _ = os.path.splitext(fname) - d["resources"][no_ext] = url_path_join(handler.base_url, "kernelspecs", name, fname) - return d - - -def is_kernelspec_model(spec_dict): - """Returns True if spec_dict is already in proper form. This will occur when using a gateway.""" - return ( - isinstance(spec_dict, dict) - and "name" in spec_dict - and "spec" in spec_dict - and "resources" in spec_dict - ) - - -class KernelSpecsAPIHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - -class MainKernelSpecHandler(KernelSpecsAPIHandler): - @web.authenticated - @authorized - async def get(self): - ksm = self.kernel_spec_manager - km = self.kernel_manager - model = {} - model["default"] = km.default_kernel_name - model["kernelspecs"] = specs = {} - kspecs = await ensure_async(ksm.get_all_specs()) - for kernel_name, kernel_info in kspecs.items(): - try: - if is_kernelspec_model(kernel_info): - d = kernel_info - else: - d = kernelspec_model( - self, - kernel_name, - kernel_info["spec"], - kernel_info["resource_dir"], - ) - except Exception: - self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True) - continue - specs[kernel_name] = d - self.set_header("Content-Type", "application/json") - self.finish(json.dumps(model)) - - -class KernelSpecHandler(KernelSpecsAPIHandler): - @web.authenticated - @authorized - async def get(self, kernel_name): - ksm = self.kernel_spec_manager - kernel_name = url_unescape(kernel_name) - try: - spec = await ensure_async(ksm.get_kernel_spec(kernel_name)) - except KeyError as e: - raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name) from e - if is_kernelspec_model(spec): - model = spec - else: - model = kernelspec_model(self, kernel_name, spec.to_dict(), spec.resource_dir) - self.set_header("Content-Type", "application/json") - self.finish(json.dumps(model)) - - -# URL to handler mappings - -kernel_name_regex = r"(?P[\w\.\-%]+)" - -default_handlers = [ - (r"/api/kernelspecs", MainKernelSpecHandler), - (r"/api/kernelspecs/%s" % kernel_name_regex, KernelSpecHandler), -] diff --git a/server/jupyter_server/services/nbconvert/__init__.py b/server/jupyter_server/services/nbconvert/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/nbconvert/handlers.py b/server/jupyter_server/services/nbconvert/handlers.py deleted file mode 100644 index d64c056..0000000 --- a/server/jupyter_server/services/nbconvert/handlers.py +++ /dev/null @@ -1,53 +0,0 @@ -import asyncio -import json - -from anyio.to_thread import run_sync -from tornado import web - -from ...base.handlers import APIHandler -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "nbconvert" - - -LOCK = asyncio.Lock() - - -class NbconvertRootHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - @web.authenticated - @authorized - async def get(self): - try: - from nbconvert.exporters import base - except ImportError as e: - raise web.HTTPError(500, "Could not import nbconvert: %s" % e) from e - res = {} - # Some exporters use the filesystem when instantiating, delegate that - # to a thread so we don't block the event loop for it. - exporters = await run_sync(base.get_export_names) - for exporter_name in exporters: - try: - async with LOCK: - exporter_class = await run_sync(base.get_exporter, exporter_name) - except ValueError: - # I think the only way this will happen is if the entrypoint - # is uninstalled while this method is running - continue - # XXX: According to the docs, it looks like this should be set to None - # if the exporter shouldn't be exposed to the front-end and a friendly - # name if it should. However, none of the built-in exports have it defined. - # if not exporter_class.export_from_notebook: - # continue - res[exporter_name] = { - "output_mimetype": exporter_class.output_mimetype, - } - - self.finish(json.dumps(res)) - - -default_handlers = [ - (r"/api/nbconvert", NbconvertRootHandler), -] diff --git a/server/jupyter_server/services/security/__init__.py b/server/jupyter_server/services/security/__init__.py deleted file mode 100644 index 9cf0d47..0000000 --- a/server/jupyter_server/services/security/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# URI for the CSP Report. Included here to prevent a cyclic dependency. -# csp_report_uri is needed both by the BaseHandler (for setting the report-uri) -# and by the CSPReportHandler (which depends on the BaseHandler). -csp_report_uri = r"/api/security/csp-report" diff --git a/server/jupyter_server/services/security/handlers.py b/server/jupyter_server/services/security/handlers.py deleted file mode 100644 index 5bf540f..0000000 --- a/server/jupyter_server/services/security/handlers.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Tornado handlers for security logging.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from tornado import web - -from . import csp_report_uri -from ...base.handlers import APIHandler -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "csp" - - -class CSPReportHandler(APIHandler): - """Accepts a content security policy violation report""" - - auth_resource = AUTH_RESOURCE - _track_activity = False - - def skip_check_origin(self): - """Don't check origin when reporting origin-check violations!""" - return True - - def check_xsrf_cookie(self): - # don't check XSRF for CSP reports - return - - @web.authenticated - @authorized - def post(self): - """Log a content security policy violation report""" - self.log.warning( - "Content security violation: %s", - self.request.body.decode("utf8", "replace"), - ) - - -default_handlers = [(csp_report_uri, CSPReportHandler)] diff --git a/server/jupyter_server/services/sessions/__init__.py b/server/jupyter_server/services/sessions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/services/sessions/handlers.py b/server/jupyter_server/services/sessions/handlers.py deleted file mode 100644 index 09e3ca3..0000000 --- a/server/jupyter_server/services/sessions/handlers.py +++ /dev/null @@ -1,195 +0,0 @@ -"""Tornado handlers for the sessions web service. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#sessions-api -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import asyncio -import json - -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import date_default as json_default -from jupyter_client.kernelspec import NoSuchKernel -from tornado import web - -from ...base.handlers import APIHandler -from jupyter_server.utils import ensure_async -from jupyter_server.utils import url_path_join -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "sessions" - - -class SessionsAPIHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - -class SessionRootHandler(SessionsAPIHandler): - @web.authenticated - @authorized - async def get(self): - # Return a list of running sessions - sm = self.session_manager - sessions = await ensure_async(sm.list_sessions()) - self.finish(json.dumps(sessions, default=json_default)) - - @web.authenticated - @authorized - async def post(self): - # Creates a new session - # (unless a session already exists for the named session) - sm = self.session_manager - - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, "No JSON data provided") - - if "notebook" in model and "path" in model["notebook"]: - self.log.warning("Sessions API changed, see updated swagger docs") - model["path"] = model["notebook"]["path"] - model["type"] = "notebook" - - try: - path = model["path"] - except KeyError as e: - raise web.HTTPError(400, "Missing field in JSON data: path") from e - - try: - mtype = model["type"] - except KeyError as e: - raise web.HTTPError(400, "Missing field in JSON data: type") from e - - name = model.get("name", None) - kernel = model.get("kernel", {}) - kernel_name = kernel.get("name", None) - kernel_id = kernel.get("id", None) - - if not kernel_id and not kernel_name: - self.log.debug("No kernel specified, using default kernel") - kernel_name = None - - exists = await ensure_async(sm.session_exists(path=path)) - if exists: - model = await sm.get_session(path=path) - else: - try: - model = await sm.create_session( - path=path, - kernel_name=kernel_name, - kernel_id=kernel_id, - name=name, - type=mtype, - ) - except NoSuchKernel: - msg = ( - "The '%s' kernel is not available. Please pick another " - "suitable kernel instead, or install that kernel." % kernel_name - ) - status_msg = "%s not found" % kernel_name - self.log.warning("Kernel not found: %s" % kernel_name) - self.set_status(501) - self.finish(json.dumps(dict(message=msg, short_message=status_msg))) - return - except Exception as e: - raise web.HTTPError(500, str(e)) from e - - location = url_path_join(self.base_url, "api", "sessions", model["id"]) - self.set_header("Location", location) - self.set_status(201) - self.finish(json.dumps(model, default=json_default)) - - -class SessionHandler(SessionsAPIHandler): - @web.authenticated - @authorized - async def get(self, session_id): - # Returns the JSON model for a single session - sm = self.session_manager - model = await sm.get_session(session_id=session_id) - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @authorized - async def patch(self, session_id): - """Patch updates sessions: - - - path updates session to track renamed paths - - kernel.name starts a new kernel with a given kernelspec - """ - sm = self.session_manager - km = self.kernel_manager - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, "No JSON data provided") - - # get the previous session model - before = await sm.get_session(session_id=session_id) - - changes = {} - if "notebook" in model and "path" in model["notebook"]: - self.log.warning("Sessions API changed, see updated swagger docs") - model["path"] = model["notebook"]["path"] - model["type"] = "notebook" - if "path" in model: - changes["path"] = model["path"] - if "name" in model: - changes["name"] = model["name"] - if "type" in model: - changes["type"] = model["type"] - if "kernel" in model: - # Kernel id takes precedence over name. - if model["kernel"].get("id") is not None: - kernel_id = model["kernel"]["id"] - if kernel_id not in km: - raise web.HTTPError(400, "No such kernel: %s" % kernel_id) - changes["kernel_id"] = kernel_id - elif model["kernel"].get("name") is not None: - kernel_name = model["kernel"]["name"] - kernel_id = await sm.start_kernel_for_session( - session_id, - kernel_name=kernel_name, - name=before["name"], - path=before["path"], - type=before["type"], - ) - changes["kernel_id"] = kernel_id - - await sm.update_session(session_id, **changes) - model = await sm.get_session(session_id=session_id) - - if model["kernel"]["id"] != before["kernel"]["id"]: - # kernel_id changed because we got a new kernel - # shutdown the old one - fut = asyncio.ensure_future(ensure_async(km.shutdown_kernel(before["kernel"]["id"]))) - # If we are not using pending kernels, wait for the kernel to shut down - if not getattr(km, "use_pending_kernels", None): - await fut - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @authorized - async def delete(self, session_id): - # Deletes the session with given session_id - sm = self.session_manager - try: - await sm.delete_session(session_id) - except KeyError as e: - # the kernel was deleted but the session wasn't! - raise web.HTTPError(410, "Kernel deleted before session") from e - self.set_status(204) - self.finish() - - -# ----------------------------------------------------------------------------- -# URL to handler mappings -# ----------------------------------------------------------------------------- - -_session_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" - -default_handlers = [ - (r"/api/sessions/%s" % _session_id_regex, SessionHandler), - (r"/api/sessions", SessionRootHandler), -] diff --git a/server/jupyter_server/services/sessions/sessionmanager.py b/server/jupyter_server/services/sessions/sessionmanager.py deleted file mode 100644 index 6a2a454..0000000 --- a/server/jupyter_server/services/sessions/sessionmanager.py +++ /dev/null @@ -1,314 +0,0 @@ -"""A base class session manager.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import pathlib -import uuid - -try: - import sqlite3 -except ImportError: - # fallback on pysqlite2 if Python was build without sqlite - from pysqlite2 import dbapi2 as sqlite3 - -from tornado import web - -from traitlets.config.configurable import LoggingConfigurable -from traitlets import Instance -from traitlets import Unicode -from traitlets import validate -from traitlets import TraitError - -from jupyter_server.utils import ensure_async -from jupyter_server.traittypes import InstanceFromClasses - - -class SessionManager(LoggingConfigurable): - - database_filepath = Unicode( - default_value=":memory:", - help=( - "The filesystem path to SQLite Database file " - "(e.g. /path/to/session_database.db). By default, the session " - "database is stored in-memory (i.e. `:memory:` setting from sqlite3) " - "and does not persist when the current Jupyter Server shuts down." - ), - ).tag(config=True) - - @validate("database_filepath") - def _validate_database_filepath(self, proposal): - value = proposal["value"] - if value == ":memory:": - return value - path = pathlib.Path(value) - if path.exists(): - # Verify that the database path is not a directory. - if path.is_dir(): - raise TraitError( - "`database_filepath` expected a file path, but the given path is a directory." - ) - # Verify that database path is an SQLite 3 Database by checking its header. - with open(value, "rb") as f: - header = f.read(100) - - if not header.startswith(b"SQLite format 3") and not header == b"": - raise TraitError("The given file is not an SQLite database file.") - return value - - kernel_manager = Instance("jupyter_server.services.kernels.kernelmanager.MappingKernelManager") - contents_manager = InstanceFromClasses( - [ - "jupyter_server.services.contents.manager.ContentsManager", - "notebook.services.contents.manager.ContentsManager", - ] - ) - - # Session database initialized below - _cursor = None - _connection = None - _columns = {"session_id", "path", "name", "type", "kernel_id"} - - @property - def cursor(self): - """Start a cursor and create a database called 'session'""" - if self._cursor is None: - self._cursor = self.connection.cursor() - self._cursor.execute( - """CREATE TABLE IF NOT EXISTS session - (session_id, path, name, type, kernel_id)""" - ) - return self._cursor - - @property - def connection(self): - """Start a database connection""" - if self._connection is None: - # Set isolation level to None to autocommit all changes to the database. - self._connection = sqlite3.connect(self.database_filepath, isolation_level=None) - self._connection.row_factory = sqlite3.Row - return self._connection - - def close(self): - """Close the sqlite connection""" - if self._cursor is not None: - self._cursor.close() - self._cursor = None - - def __del__(self): - """Close connection once SessionManager closes""" - self.close() - - async def session_exists(self, path): - """Check to see if the session of a given name exists""" - exists = False - self.cursor.execute("SELECT * FROM session WHERE path=?", (path,)) - row = self.cursor.fetchone() - if row is not None: - # Note, although we found a row for the session, the associated kernel may have - # been culled or died unexpectedly. If that's the case, we should delete the - # row, thereby terminating the session. This can be done via a call to - # row_to_model that tolerates that condition. If row_to_model returns None, - # we'll return false, since, at that point, the session doesn't exist anyway. - model = await self.row_to_model(row, tolerate_culled=True) - if model is not None: - exists = True - return exists - - def new_session_id(self): - "Create a uuid for a new session" - return str(uuid.uuid4()) - - async def create_session( - self, path=None, name=None, type=None, kernel_name=None, kernel_id=None - ): - """Creates a session and returns its model""" - session_id = self.new_session_id() - if kernel_id is not None and kernel_id in self.kernel_manager: - pass - else: - kernel_id = await self.start_kernel_for_session( - session_id, path, name, type, kernel_name - ) - result = await self.save_session( - session_id, path=path, name=name, type=type, kernel_id=kernel_id - ) - return result - - async def start_kernel_for_session(self, session_id, path, name, type, kernel_name): - """Start a new kernel for a given session.""" - # allow contents manager to specify kernels cwd - kernel_path = self.contents_manager.get_kernel_path(path=path) - kernel_id = await self.kernel_manager.start_kernel( - path=kernel_path, kernel_name=kernel_name - ) - return kernel_id - - async def save_session(self, session_id, path=None, name=None, type=None, kernel_id=None): - """Saves the items for the session with the given session_id - - Given a session_id (and any other of the arguments), this method - creates a row in the sqlite session database that holds the information - for a session. - - Parameters - ---------- - session_id : str - uuid for the session; this method must be given a session_id - path : str - the path for the given session - name: str - the name of the session - type: string - the type of the session - kernel_id : str - a uuid for the kernel associated with this session - - Returns - ------- - model : dict - a dictionary of the session model - """ - self.cursor.execute( - "INSERT INTO session VALUES (?,?,?,?,?)", - (session_id, path, name, type, kernel_id), - ) - result = await self.get_session(session_id=session_id) - return result - - async def get_session(self, **kwargs): - """Returns the model for a particular session. - - Takes a keyword argument and searches for the value in the session - database, then returns the rest of the session's info. - - Parameters - ---------- - **kwargs : keyword argument - must be given one of the keywords and values from the session database - (i.e. session_id, path, name, type, kernel_id) - - Returns - ------- - model : dict - returns a dictionary that includes all the information from the - session described by the kwarg. - """ - if not kwargs: - raise TypeError("must specify a column to query") - - conditions = [] - for column in kwargs.keys(): - if column not in self._columns: - raise TypeError("No such column: %r", column) - conditions.append("%s=?" % column) - - query = "SELECT * FROM session WHERE %s" % (" AND ".join(conditions)) - - self.cursor.execute(query, list(kwargs.values())) - try: - row = self.cursor.fetchone() - except KeyError: - # The kernel is missing, so the session just got deleted. - row = None - - if row is None: - q = [] - for key, value in kwargs.items(): - q.append("%s=%r" % (key, value)) - - raise web.HTTPError(404, "Session not found: %s" % (", ".join(q))) - - try: - model = await self.row_to_model(row) - except KeyError as e: - raise web.HTTPError(404, "Session not found: %s" % str(e)) - return model - - async def update_session(self, session_id, **kwargs): - """Updates the values in the session database. - - Changes the values of the session with the given session_id - with the values from the keyword arguments. - - Parameters - ---------- - session_id : str - a uuid that identifies a session in the sqlite3 database - **kwargs : str - the key must correspond to a column title in session database, - and the value replaces the current value in the session - with session_id. - """ - await self.get_session(session_id=session_id) - - if not kwargs: - # no changes - return - - sets = [] - for column in kwargs.keys(): - if column not in self._columns: - raise TypeError("No such column: %r" % column) - sets.append("%s=?" % column) - query = "UPDATE session SET %s WHERE session_id=?" % (", ".join(sets)) - self.cursor.execute(query, list(kwargs.values()) + [session_id]) - - def kernel_culled(self, kernel_id): - """Checks if the kernel is still considered alive and returns true if its not found.""" - return kernel_id not in self.kernel_manager - - async def row_to_model(self, row, tolerate_culled=False): - """Takes sqlite database session row and turns it into a dictionary""" - kernel_culled = await ensure_async(self.kernel_culled(row["kernel_id"])) - if kernel_culled: - # The kernel was culled or died without deleting the session. - # We can't use delete_session here because that tries to find - # and shut down the kernel - so we'll delete the row directly. - # - # If caller wishes to tolerate culled kernels, log a warning - # and return None. Otherwise, raise KeyError with a similar - # message. - self.cursor.execute("DELETE FROM session WHERE session_id=?", (row["session_id"],)) - msg = ( - "Kernel '{kernel_id}' appears to have been culled or died unexpectedly, " - "invalidating session '{session_id}'. The session has been removed.".format( - kernel_id=row["kernel_id"], session_id=row["session_id"] - ) - ) - if tolerate_culled: - self.log.warning(msg + " Continuing...") - return - raise KeyError(msg) - - kernel_model = await ensure_async(self.kernel_manager.kernel_model(row["kernel_id"])) - model = { - "id": row["session_id"], - "path": row["path"], - "name": row["name"], - "type": row["type"], - "kernel": kernel_model, - } - if row["type"] == "notebook": - # Provide the deprecated API. - model["notebook"] = {"path": row["path"], "name": row["name"]} - return model - - async def list_sessions(self): - """Returns a list of dictionaries containing all the information from - the session database""" - c = self.cursor.execute("SELECT * FROM session") - result = [] - # We need to use fetchall() here, because row_to_model can delete rows, - # which messes up the cursor if we're iterating over rows. - for row in c.fetchall(): - try: - model = await self.row_to_model(row) - result.append(model) - except KeyError: - pass - return result - - async def delete_session(self, session_id): - """Deletes the row in the session database with given session_id""" - session = await self.get_session(session_id=session_id) - await ensure_async(self.kernel_manager.shutdown_kernel(session["kernel"]["id"])) - self.cursor.execute("DELETE FROM session WHERE session_id=?", (session_id,)) diff --git a/server/jupyter_server/services/shutdown.py b/server/jupyter_server/services/shutdown.py deleted file mode 100644 index a77e900..0000000 --- a/server/jupyter_server/services/shutdown.py +++ /dev/null @@ -1,28 +0,0 @@ -"""HTTP handler to shut down the Jupyter server. -""" -from tornado import ioloop -from tornado import web - -from jupyter_server.auth import authorized -from jupyter_server.base.handlers import JupyterHandler - - -AUTH_RESOURCE = "server" - - -class ShutdownHandler(JupyterHandler): - auth_resource = AUTH_RESOURCE - - @web.authenticated - @authorized - async def post(self): - self.log.info("Shutting down on /api/shutdown request.") - - await self.serverapp._cleanup() - - ioloop.IOLoop.current().stop() - - -default_handlers = [ - (r"/api/shutdown", ShutdownHandler), -] diff --git a/server/jupyter_server/static/favicon.ico b/server/jupyter_server/static/favicon.ico deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/favicon.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-busy-1.ico b/server/jupyter_server/static/favicons/favicon-busy-1.ico deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-busy-1.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-busy-2.ico b/server/jupyter_server/static/favicons/favicon-busy-2.ico deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-busy-2.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-busy-3.ico b/server/jupyter_server/static/favicons/favicon-busy-3.ico deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-busy-3.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-file.ico b/server/jupyter_server/static/favicons/favicon-file.ico deleted file mode 100644 index 8167018..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-file.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-notebook.ico b/server/jupyter_server/static/favicons/favicon-notebook.ico deleted file mode 100644 index 4537e2d..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-notebook.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon-terminal.ico b/server/jupyter_server/static/favicons/favicon-terminal.ico deleted file mode 100644 index ace499a..0000000 Binary files a/server/jupyter_server/static/favicons/favicon-terminal.ico and /dev/null differ diff --git a/server/jupyter_server/static/favicons/favicon.ico b/server/jupyter_server/static/favicons/favicon.ico deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/favicons/favicon.ico and /dev/null differ diff --git a/server/jupyter_server/static/logo/logo.png b/server/jupyter_server/static/logo/logo.png deleted file mode 100644 index 00ac191..0000000 Binary files a/server/jupyter_server/static/logo/logo.png and /dev/null differ diff --git a/server/jupyter_server/static/style/index.css b/server/jupyter_server/static/style/index.css deleted file mode 100644 index 3e50941..0000000 --- a/server/jupyter_server/static/style/index.css +++ /dev/null @@ -1,91 +0,0 @@ -#jupyter_server { - padding-left: 0px; - padding-top: 1px; - padding-bottom: 1px; -} - -#jupyter_server img { - height: 28px; -} - -#jupyter-main-app { - padding-top: 50px; - text-align: center; -} - -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 1.42857143; - color: #000; -} - -body > #header { - display: block; - background-color: #fff; - position: relative; - z-index: 100; -} - -body > #header #header-container { - display: flex; - flex-direction: row; - justify-content: space-between; - padding: 5px; - padding-top: 5px; - padding-bottom: 5px; - padding-bottom: 5px; - padding-top: 5px; - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -body > #header .header-bar { - width: 100%; - height: 1px; - background: #e7e7e7; - margin-bottom: -1px; -} - -.navbar-brand { - float: left; - height: 30px; - padding: 6px 0px; - padding-top: 6px; - padding-bottom: 6px; - padding-left: 0px; - font-size: 17px; - line-height: 18px; -} - -.navbar-brand, -.navbar-nav > li > a { - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); -} - -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none; -} - -.center-nav { - display: inline-block; - margin-bottom: -4px; -} - -div.error { - margin: 2em; - text-align: center; -} - -div.error > h1 { - font-size: 500%; - line-height: normal; -} - -div.error > p { - font-size: 200%; - line-height: normal; -} diff --git a/server/jupyter_server/templates/404.html b/server/jupyter_server/templates/404.html deleted file mode 100644 index e403081..0000000 --- a/server/jupyter_server/templates/404.html +++ /dev/null @@ -1,4 +0,0 @@ -{% extends "error.html" %} -{% block error_detail %} -

    {% trans %}You are requesting a page that does not exist!{% endtrans %}

    -{% endblock %} diff --git a/server/jupyter_server/templates/browser-open.html b/server/jupyter_server/templates/browser-open.html deleted file mode 100644 index 4217b0f..0000000 --- a/server/jupyter_server/templates/browser-open.html +++ /dev/null @@ -1,18 +0,0 @@ -{# This template is not served, but written as a file to open in the browser, - passing the token without putting it in a command-line argument. #} - - - - - - Opening ElixirNote Application - - - -

    - This page should redirect you to a ElixirNote application. If it doesn't, - click here to go to ElixirNote. -

    - - - diff --git a/server/jupyter_server/templates/error.html b/server/jupyter_server/templates/error.html deleted file mode 100644 index 17adc7d..0000000 --- a/server/jupyter_server/templates/error.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "page.html" %} - -{% block stylesheet %} -{{super()}} - -{% endblock %} -{% block site %} - -
    - {% block h1_error %} -

    {{status_code}} : {{status_message}}

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

    {% trans %}The error was:{% endtrans %}

    -
    -
    {{message}}
    -
    - {% endif %} - {% endblock error_detail %} -
    - -{% endblock %} - -{% block script %} -{% endblock script %} diff --git a/server/jupyter_server/templates/login.html b/server/jupyter_server/templates/login.html deleted file mode 100644 index d375132..0000000 --- a/server/jupyter_server/templates/login.html +++ /dev/null @@ -1,117 +0,0 @@ -{% extends "page.html" %} - - -{% block stylesheet %} -{% endblock %} - -{% block site %} - -
    - {% if login_available %} - {# login_available means password-login is allowed. Show the form. #} -
    - -
    - {% else %} -

    {% trans %}No login available, you shouldn't be seeing this page.{% endtrans %}

    - {% endif %} - {% if message %} -
    - {% for key in message %} -
    - {{message[key]}} -
    - {% endfor %} -
    - {% endif %} - {% if token_available %} - {% block token_message %} -
    -

    - Token authentication is enabled -

    -

    - If no password has been configured, you need to open the - server with its login token in the URL, or paste it above. - This requirement will be lifted if you - - enable a password. -

    -

    - The command: -

    elixirnote server list
    - will show you the URLs of running servers with their tokens, - which you can copy and paste into your browser. For example: -

    -
    Currently running servers:
    -http://localhost:8888/?token=c8de56fa... :: /Users/you/notebooks
    -
    -

    - or you can paste just the token value into the password field on this - page. -

    -

    - See - - the documentation on how to enable a password - - in place of token authentication, - if you would like to avoid dealing with random tokens. -

    -

    - Cookies are required for authenticated access to the Kennen server. -

    - {% if allow_password_change %} -

    {% trans %}Setup a Password{% endtrans %}

    -

    You can also setup a password by entering your token and a new password - on the fields below:

    -
    - {{ xsrf_form_html() | safe }} -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endif %} - -
    - {% endblock token_message %} - {% endif %} -
    - -{% endblock %} - - -{% block script %} -{% endblock %} diff --git a/server/jupyter_server/templates/logout.html b/server/jupyter_server/templates/logout.html deleted file mode 100644 index 81121e1..0000000 --- a/server/jupyter_server/templates/logout.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "page.html" %} - -{# This template is rendered in response to an authenticated request, so the -user is technically logged in. But when the user sees it, the cookie is -cleared by the Javascript, so we should render this as if the user was logged -out, without e.g. authentication tokens. -#} -{% set logged_in = False %} - -{% block stylesheet %} -{% endblock %} - -{% block site %} - -
    - - {% if message %} - {% for key in message %} -
    - {{message[key]}} -
    - {% endfor %} - {% endif %} - - {% if not login_available %} - {% trans %}Proceed to the dashboard{% endtrans %}. - {% else %} - {% trans %}Proceed to the login page{% endtrans %}. - {% endif %} - - -
    - - {% endblock %} diff --git a/server/jupyter_server/templates/main.html b/server/jupyter_server/templates/main.html deleted file mode 100644 index 0aafe76..0000000 --- a/server/jupyter_server/templates/main.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "page.html" %} - -{% block site %} -
    -

    A ElixirNote Server is running.

    -
    -{% endblock site %} diff --git a/server/jupyter_server/templates/page.html b/server/jupyter_server/templates/page.html deleted file mode 100644 index 6c9fcda..0000000 --- a/server/jupyter_server/templates/page.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - {% block title %}ElixirNote Server{% endblock %} - {% block favicon %} - {% endblock %} - - - - - - - {% block stylesheet %} - {% endblock stylesheet %} - - {% block meta %} - {% endblock meta %} - - - - - - - - - -
    - {% block site %} - {% endblock site %} -
    - - {% block after_site %} - {% endblock after_site %} - - {% block script %} - {% endblock script %} - - - - - diff --git a/server/jupyter_server/templates/view.html b/server/jupyter_server/templates/view.html deleted file mode 100644 index 553712a..0000000 --- a/server/jupyter_server/templates/view.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - ElixirNote - - - - - -
    - -
    - - - diff --git a/server/jupyter_server/terminal/__init__.py b/server/jupyter_server/terminal/__init__.py deleted file mode 100644 index 8bac278..0000000 --- a/server/jupyter_server/terminal/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -import os -import sys - -import terminado - -from ..utils import check_version - -if not check_version(terminado.__version__, "0.8.3"): - raise ImportError("terminado >= 0.8.3 required, found %s" % terminado.__version__) - -from ipython_genutils.py3compat import which -from jupyter_server.utils import url_path_join as ujoin -from . import api_handlers -from .handlers import TermSocket -from .terminalmanager import TerminalManager - - -def initialize(webapp, root_dir, connection_url, settings): - if os.name == "nt": - default_shell = "powershell.exe" - else: - default_shell = which("sh") - shell_override = settings.get("shell_command") - shell = [os.environ.get("SHELL") or default_shell] if shell_override is None else shell_override - # When the notebook server is not running in a terminal (e.g. when - # it's launched by a JupyterHub spawner), it's likely that the user - # environment hasn't been fully set up. In that case, run a login - # shell to automatically source /etc/profile and the like, unless - # the user has specifically set a preferred shell command. - if os.name != "nt" and shell_override is None and not sys.stdout.isatty(): - shell.append("-l") - terminal_manager = webapp.settings["terminal_manager"] = TerminalManager( - shell_command=shell, - extra_env={ - "JUPYTER_SERVER_ROOT": root_dir, - "JUPYTER_SERVER_URL": connection_url, - }, - parent=webapp.settings["serverapp"], - ) - terminal_manager.log = webapp.settings["serverapp"].log - base_url = webapp.settings["base_url"] - handlers = [ - ( - ujoin(base_url, r"/terminals/websocket/(\w+)"), - TermSocket, - {"term_manager": terminal_manager}, - ), - (ujoin(base_url, r"/api/terminals"), api_handlers.TerminalRootHandler), - (ujoin(base_url, r"/api/terminals/(\w+)"), api_handlers.TerminalHandler), - ] - webapp.add_handlers(".*$", handlers) diff --git a/server/jupyter_server/terminal/api_handlers.py b/server/jupyter_server/terminal/api_handlers.py deleted file mode 100644 index 99f7e91..0000000 --- a/server/jupyter_server/terminal/api_handlers.py +++ /dev/null @@ -1,47 +0,0 @@ -import json - -from tornado import web - -from ..base.handlers import APIHandler -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "terminals" - - -class TerminalAPIHandler(APIHandler): - auth_resource = AUTH_RESOURCE - - -class TerminalRootHandler(TerminalAPIHandler): - @web.authenticated - @authorized - def get(self): - models = self.terminal_manager.list() - self.finish(json.dumps(models)) - - @web.authenticated - @authorized - def post(self): - """POST /terminals creates a new terminal and redirects to it""" - data = self.get_json_body() or {} - - model = self.terminal_manager.create(**data) - self.finish(json.dumps(model)) - - -class TerminalHandler(TerminalAPIHandler): - SUPPORTED_METHODS = ("GET", "DELETE") - - @web.authenticated - @authorized - def get(self, name): - model = self.terminal_manager.get(name) - self.finish(json.dumps(model)) - - @web.authenticated - @authorized - async def delete(self, name): - await self.terminal_manager.terminate(name, force=True) - self.set_status(204) - self.finish() diff --git a/server/jupyter_server/terminal/handlers.py b/server/jupyter_server/terminal/handlers.py deleted file mode 100644 index 7c11170..0000000 --- a/server/jupyter_server/terminal/handlers.py +++ /dev/null @@ -1,50 +0,0 @@ -# encoding: utf-8 -"""Tornado handlers for the terminal emulator.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import terminado -from tornado import web - -from ..base.handlers import JupyterHandler -from ..base.zmqhandlers import WebSocketMixin -from jupyter_server._tz import utcnow - -AUTH_RESOURCE = "terminals" - - -class TermSocket(WebSocketMixin, JupyterHandler, terminado.TermSocket): - - auth_resource = AUTH_RESOURCE - - def origin_check(self): - """Terminado adds redundant origin_check - Tornado already calls check_origin, so don't do anything here. - """ - return True - - def get(self, *args, **kwargs): - user = self.current_user - - if not user: - raise web.HTTPError(403) - - if not self.authorizer.is_authorized(self, user, "execute", self.auth_resource): - raise web.HTTPError(403) - - if not args[0] in self.term_manager.terminals: - raise web.HTTPError(404) - return super(TermSocket, self).get(*args, **kwargs) - - def on_message(self, message): - super(TermSocket, self).on_message(message) - self._update_activity() - - def write_message(self, message, binary=False): - super(TermSocket, self).write_message(message, binary=binary) - self._update_activity() - - def _update_activity(self): - self.application.settings["terminal_last_activity"] = utcnow() - # terminal may not be around on deletion/cull - if self.term_name in self.terminal_manager.terminals: - self.terminal_manager.terminals[self.term_name].last_activity = utcnow() diff --git a/server/jupyter_server/terminal/terminalmanager.py b/server/jupyter_server/terminal/terminalmanager.py deleted file mode 100644 index 1db545e..0000000 --- a/server/jupyter_server/terminal/terminalmanager.py +++ /dev/null @@ -1,169 +0,0 @@ -"""A MultiTerminalManager for use in the notebook webserver -- raises HTTPErrors -- creates REST API models -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from datetime import timedelta - -import terminado -from tornado import web -from tornado.ioloop import IOLoop -from tornado.ioloop import PeriodicCallback -from traitlets import Integer -from traitlets.config import LoggingConfigurable - -from ..prometheus.metrics import TERMINAL_CURRENTLY_RUNNING_TOTAL -from jupyter_server._tz import isoformat -from jupyter_server._tz import utcnow - - -class TerminalManager(LoggingConfigurable, terminado.NamedTermManager): - """ """ - - _culler_callback = None - - _initialized_culler = False - - cull_inactive_timeout = Integer( - 0, - config=True, - help="""Timeout (in seconds) in which a terminal has been inactive and ready to be culled. - Values of 0 or lower disable culling.""", - ) - - cull_interval_default = 300 # 5 minutes - cull_interval = Integer( - cull_interval_default, - config=True, - help="""The interval (in seconds) on which to check for terminals exceeding the inactive timeout value.""", - ) - - # ------------------------------------------------------------------------- - # Methods for managing terminals - # ------------------------------------------------------------------------- - def __init__(self, *args, **kwargs): - super(TerminalManager, self).__init__(*args, **kwargs) - - def create(self, **kwargs): - """Create a new terminal.""" - name, term = self.new_named_terminal(**kwargs) - # Monkey-patch last-activity, similar to kernels. Should we need - # more functionality per terminal, we can look into possible sub- - # classing or containment then. - term.last_activity = utcnow() - model = self.get_terminal_model(name) - # Increase the metric by one because a new terminal was created - TERMINAL_CURRENTLY_RUNNING_TOTAL.inc() - # Ensure culler is initialized - self._initialize_culler() - return model - - def get(self, name): - """Get terminal 'name'.""" - model = self.get_terminal_model(name) - return model - - def list(self): - """Get a list of all running terminals.""" - models = [self.get_terminal_model(name) for name in self.terminals] - - # Update the metric below to the length of the list 'terms' - TERMINAL_CURRENTLY_RUNNING_TOTAL.set(len(models)) - return models - - async def terminate(self, name, force=False): - """Terminate terminal 'name'.""" - self._check_terminal(name) - await super(TerminalManager, self).terminate(name, force=force) - - # Decrease the metric below by one - # because a terminal has been shutdown - TERMINAL_CURRENTLY_RUNNING_TOTAL.dec() - - async def terminate_all(self): - """Terminate all terminals.""" - terms = [name for name in self.terminals] - for term in terms: - await self.terminate(term, force=True) - - def get_terminal_model(self, name): - """Return a JSON-safe dict representing a terminal. - For use in representing terminals in the JSON APIs. - """ - self._check_terminal(name) - term = self.terminals[name] - model = { - "name": name, - "last_activity": isoformat(term.last_activity), - } - return model - - def _check_terminal(self, name): - """Check a that terminal 'name' exists and raise 404 if not.""" - if name not in self.terminals: - raise web.HTTPError(404, "Terminal not found: %s" % name) - - def _initialize_culler(self): - """Start culler if 'cull_inactive_timeout' is greater than zero. - Regardless of that value, set flag that we've been here. - """ - if not self._initialized_culler and self.cull_inactive_timeout > 0: - if self._culler_callback is None: - loop = IOLoop.current() - if self.cull_interval <= 0: # handle case where user set invalid value - self.log.warning( - "Invalid value for 'cull_interval' detected (%s) - using default value (%s).", - self.cull_interval, - self.cull_interval_default, - ) - self.cull_interval = self.cull_interval_default - self._culler_callback = PeriodicCallback( - self._cull_terminals, 1000 * self.cull_interval - ) - self.log.info( - "Culling terminals with inactivity > %s seconds at %s second intervals ...", - self.cull_inactive_timeout, - self.cull_interval, - ) - self._culler_callback.start() - - self._initialized_culler = True - - async def _cull_terminals(self): - self.log.debug( - "Polling every %s seconds for terminals inactive for > %s seconds...", - self.cull_interval, - self.cull_inactive_timeout, - ) - # Create a separate list of terminals to avoid conflicting updates while iterating - for name in list(self.terminals): - try: - await self._cull_inactive_terminal(name) - except Exception as e: - self.log.exception( - "The following exception was encountered while checking the " - "activity of terminal {}: {}".format(name, e) - ) - - async def _cull_inactive_terminal(self, name): - try: - term = self.terminals[name] - except KeyError: - return # KeyErrors are somewhat expected since the terminal can be terminated as the culling check is made. - - self.log.debug("name=%s, last_activity=%s", name, term.last_activity) - if hasattr(term, "last_activity"): - dt_now = utcnow() - dt_inactive = dt_now - term.last_activity - # Compute idle properties - is_time = dt_inactive > timedelta(seconds=self.cull_inactive_timeout) - # Cull the kernel if all three criteria are met - if is_time: - inactivity = int(dt_inactive.total_seconds()) - self.log.warning( - "Culling terminal '%s' due to %s seconds of inactivity.", - name, - inactivity, - ) - await self.terminate(name, force=True) diff --git a/server/jupyter_server/tests/__init__.py b/server/jupyter_server/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/auth/__init__.py b/server/jupyter_server/tests/auth/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/auth/test_authorizer.py b/server/jupyter_server/tests/auth/test_authorizer.py deleted file mode 100644 index a045320..0000000 --- a/server/jupyter_server/tests/auth/test_authorizer.py +++ /dev/null @@ -1,277 +0,0 @@ -"""Tests for authorization""" -import json - -import pytest -from jupyter_client.kernelspec import NATIVE_KERNEL_NAME -from nbformat import writes -from nbformat.v4 import new_notebook -from tornado.httpclient import HTTPClientError -from tornado.websocket import WebSocketHandler - -from jupyter_server.auth.authorizer import Authorizer -from jupyter_server.auth.utils import HTTP_METHOD_TO_AUTH_ACTION -from jupyter_server.auth.utils import match_url_to_resource -from jupyter_server.services.security import csp_report_uri - - -class AuthorizerforTesting(Authorizer): - - # Set these class attributes from within a test - # to verify that they match the arguments passed - # by the REST API. - permissions = {} - - def normalize_url(https://github.com/self,%20path): - """Drop the base URL and make sure path leads with a /""" - base_url = self.parent.base_url - # Remove base_url - if path.startswith(base_url): - path = path[len(base_url) :] - # Make sure path starts with / - if not path.startswith("/"): - path = "/" + path - return path - - def is_authorized(self, handler, user, action, resource): - # Parse Request - if isinstance(handler, WebSocketHandler): - method = "WEBSOCKET" - else: - method = handler.request.method - url = self.normalize_url(https://github.com/handler.request.path) - - # Map request parts to expected action and resource. - expected_action = HTTP_METHOD_TO_AUTH_ACTION[method] - expected_resource = match_url_to_resource(url) - - # Assert that authorization layer returns the - # correct action + resource. - assert action == expected_action - assert resource == expected_resource - - # Now, actually apply the authorization layer. - return all( - [ - action in self.permissions.get("actions", []), - resource in self.permissions.get("resources", []), - ] - ) - - -@pytest.fixture -def jp_server_config(): - return {"ServerApp": {"authorizer_class": AuthorizerforTesting}} - - -@pytest.fixture -def send_request(jp_fetch, jp_ws_fetch): - """Send to Jupyter Server and return response code.""" - - async def _(url, **fetch_kwargs): - if url.endswith("channels") or "/websocket/" in url: - fetch = jp_ws_fetch - else: - fetch = jp_fetch - - try: - r = await fetch(url, **fetch_kwargs, allow_nonstandard_methods=True) - code = r.code - except HTTPClientError as err: - code = err.code - else: - if fetch is jp_ws_fetch: - r.close() - - print(code, url, fetch_kwargs) - return code - - return _ - - -HTTP_REQUESTS = [ - { - "method": "GET", - "url": "/view/{nbpath}", - }, - { - "method": "GET", - "url": "/api/contents", - }, - { - "method": "POST", - "url": "/api/contents", - "body": json.dumps({"type": "directory"}), - }, - { - "method": "PUT", - "url": "/api/contents/foo", - "body": json.dumps({"type": "directory"}), - }, - { - "method": "PATCH", - "url": "/api/contents/{nbpath}", - "body": json.dumps({"path": "/newpath"}), - }, - { - "method": "DELETE", - "url": "/api/contents/{nbpath}", - }, - { - "method": "GET", - "url": "/api/kernels", - }, - { - "method": "GET", - "url": "/api/kernels/{kernel_id}", - }, - { - "method": "GET", - "url": "/api/kernels/{kernel_id}/channels", - }, - { - "method": "POST", - "url": "/api/kernels/{kernel_id}/interrupt", - }, - { - "method": "POST", - "url": "/api/kernels/{kernel_id}/restart", - }, - { - "method": "DELETE", - "url": "/api/kernels/{kernel_id}", - }, - { - "method": "POST", - "url": "/api/kernels", - }, - {"method": "GET", "url": "/api/kernelspecs"}, - {"method": "GET", "url": "/api/kernelspecs/{kernelspec}"}, - {"method": "GET", "url": "/api/nbconvert"}, - {"method": "GET", "url": "/api/spec.yaml"}, - {"method": "GET", "url": "/api/status"}, - {"method": "GET", "url": "/api/config/foo"}, - {"method": "PUT", "url": "/api/config/foo", "body": "{}"}, - {"method": "PATCH", "url": "/api/config/foo", "body": "{}"}, - { - "method": "POST", - "url": "/".join(tuple(csp_report_uri.split("/")[1:])), - }, - { - "method": "GET", - "url": "/api/sessions", - }, - { - "method": "GET", - "url": "/api/sessions/{session_id}", - }, - {"method": "PATCH", "url": "/api/sessions/{session_id}", "body": "{}"}, - { - "method": "DELETE", - "url": "/api/sessions/{session_id}", - }, - { - "method": "POST", - "url": "/api/sessions", - "body": json.dumps({"path": "foo", "type": "bar"}), - }, - { - "method": "POST", - "url": "/api/terminals", - "body": "", - }, - { - "method": "GET", - "url": "/api/terminals", - }, - { - "method": "GET", - "url": "/terminals/websocket/{term_name}", - }, - { - "method": "DELETE", - "url": "/api/terminals/{term_name}", - }, -] - -HTTP_REQUESTS_PARAMETRIZED = [(req["method"], req["url"], req.get("body")) for req in HTTP_REQUESTS] - -# -------- Test scenarios ----------- - - -@pytest.mark.parametrize("method, url, body", HTTP_REQUESTS_PARAMETRIZED) -@pytest.mark.parametrize("allowed", (True, False)) -async def test_authorized_requests( - request, - io_loop, - send_request, - tmp_path, - jp_serverapp, - method, - url, - body, - allowed, -): - ### Setup stuff for the Contents API - # Add a notebook on disk - contents_dir = tmp_path / jp_serverapp.root_dir - p = contents_dir / "dir_for_testing" - p.mkdir(parents=True, exist_ok=True) - - # Create a notebook - nb = writes(new_notebook(), version=4) - nbname = p.joinpath("nb_for_testing.ipynb") - nbname.write_text(nb, encoding="utf-8") - - ### Setup - nbpath = "dir_for_testing/nb_for_testing.ipynb" - kernelspec = NATIVE_KERNEL_NAME - km = jp_serverapp.kernel_manager - - if "session" in url: - request.addfinalizer(lambda: io_loop.run_sync(km.shutdown_all)) - session_model = await jp_serverapp.session_manager.create_session(path="foo") - session_id = session_model["id"] - - if "kernel" in url: - request.addfinalizer(lambda: io_loop.run_sync(km.shutdown_all)) - kernel_id = await km.start_kernel() - kernel = km.get_kernel(kernel_id) - # kernels take a moment to be ready - # wait for it to respond - kc = kernel.client() - kc.start_channels() - await kc.wait_for_ready() - kc.stop_channels() - - if "terminal" in url: - term_manager = jp_serverapp.web_app.settings["terminal_manager"] - request.addfinalizer(lambda: io_loop.run_sync(term_manager.terminate_all)) - term_model = term_manager.create() - term_name = term_model["name"] - - url = url.format(**locals()) - if allowed: - # Create a server with full permissions - permissions = { - "actions": ["read", "write", "execute"], - "resources": [ - "contents", - "kernels", - "kernelspecs", - "nbconvert", - "sessions", - "api", - "config", - "csp", - "server", - "terminals", - ], - } - expected_codes = {200, 201, 204, None} # Websockets don't return a code - else: - permissions = {"actions": [], "resources": []} - expected_codes = {403} - jp_serverapp.authorizer.permissions = permissions - - code = await send_request(url, body=body, method=method) - assert code in expected_codes diff --git a/server/jupyter_server/tests/auth/test_login.py b/server/jupyter_server/tests/auth/test_login.py deleted file mode 100644 index 6f1c358..0000000 --- a/server/jupyter_server/tests/auth/test_login.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Tests for login redirects""" -from functools import partial -from urllib.parse import urlencode - -import pytest -from tornado.httpclient import HTTPClientError -from tornado.httputil import parse_cookie -from tornado.httputil import url_concat - -from jupyter_server.utils import url_path_join - - -# override default config to ensure a non-empty base url is used -@pytest.fixture -def jp_base_url(): - return "/a%40b/" - - -@pytest.fixture -def jp_server_config(jp_base_url): - return { - "ServerApp": { - "base_url": jp_base_url, - }, - } - - -async def _login(jp_serverapp, http_server_client, jp_base_url, next): - # first: request login page with no creds - login_url = url_path_join(jp_base_url, "login") - first = await http_server_client.fetch(login_url) - cookie_header = first.headers["Set-Cookie"] - cookies = parse_cookie(cookie_header) - - # second, submit login form with credentials - try: - resp = await http_server_client.fetch( - url_concat(login_url, {"next": next}), - method="POST", - body=urlencode( - { - "password": jp_serverapp.token, - "_xsrf": cookies.get("_xsrf", ""), - } - ), - headers={"Cookie": cookie_header}, - follow_redirects=False, - ) - except HTTPClientError as e: - if e.code != 302: - raise - return e.response.headers["Location"] - else: - assert resp.code == 302, "Should have returned a redirect!" - - -@pytest.fixture -def login(jp_serverapp, http_server_client, jp_base_url): - """Fixture to return a function to login to a Jupyter server - - by submitting the login page form - """ - yield partial(_login, jp_serverapp, http_server_client, jp_base_url) - - -@pytest.mark.parametrize( - "bad_next", - ( - r"\\tree", - "//some-host", - "//host{base_url}tree", - "https://google.com/", - "/absolute/not/base_url", - ), -) -async def test_next_bad(login, jp_base_url, bad_next): - bad_next = bad_next.format(base_url=jp_base_url) - url = await login(bad_next) - assert url == jp_base_url - - -@pytest.mark.parametrize( - "next_path", - ( - "tree/", - "//{base_url}tree", - "notebooks/notebook.ipynb", - "tree//something", - ), -) -async def test_next_ok(login, jp_base_url, next_path): - next_path = next_path.format(base_url=jp_base_url) - expected = jp_base_url + next_path - actual = await login(next=expected) - assert actual == expected diff --git a/server/jupyter_server/tests/auth/test_security.py b/server/jupyter_server/tests/auth/test_security.py deleted file mode 100644 index 1a3f172..0000000 --- a/server/jupyter_server/tests/auth/test_security.py +++ /dev/null @@ -1,31 +0,0 @@ -from jupyter_server.auth.security import passwd -from jupyter_server.auth.security import passwd_check - - -def test_passwd_structure(): - p = passwd("passphrase") - algorithm, hashed = p.split(":") - assert algorithm == "argon2", algorithm - assert hashed.startswith("$argon2id$"), hashed - - -def test_roundtrip(): - p = passwd("passphrase") - assert passwd_check(p, "passphrase") - - -def test_bad(): - p = passwd("passphrase") - assert not passwd_check(p, p) - assert not passwd_check(p, "a:b:c:d") - assert not passwd_check(p, "a:b") - - -def test_passwd_check_unicode(): - # GH issue #4524 - phash = "sha1:23862bc21dd3:7a415a95ae4580582e314072143d9c382c491e4f" - assert passwd_check(phash, "łeÂļŧ←↓→") - phash = ( - "argon2:$argon2id$v=19$m=10240,t=10,p=8$" "qjjDiZUofUVVnrVYxacnbA$l5pQq1bJ8zglGT2uXP6iOg" - ) - assert passwd_check(phash, "łeÂļŧ←↓→") diff --git a/server/jupyter_server/tests/auth/test_utils.py b/server/jupyter_server/tests/auth/test_utils.py deleted file mode 100644 index 4927c22..0000000 --- a/server/jupyter_server/tests/auth/test_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -import pytest - -from jupyter_server.auth.utils import match_url_to_resource - - -@pytest.mark.parametrize( - "url,expected_resource", - [ - ("/api/kernels", "kernels"), - ("/api/kernelspecs", "kernelspecs"), - ("/api/contents", "contents"), - ("/api/sessions", "sessions"), - ("/api/terminals", "terminals"), - ("/api/nbconvert", "nbconvert"), - ("/api/config/x", "config"), - ("/api/shutdown", "server"), - ("/nbconvert/py", "nbconvert"), - ], -) -def test_match_url_to_resource(url, expected_resource): - resource = match_url_to_resource(url) - assert resource == expected_resource - - -@pytest.mark.parametrize( - "url", - [ - "/made/up/url", - # Misspell. - "/api/kernel", - # Not a resource - "/tree", - ], -) -def test_bad_match_url_to_resource(url): - resource = match_url_to_resource(url) - assert resource is None diff --git a/server/jupyter_server/tests/extension/__init__.py b/server/jupyter_server/tests/extension/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/extension/conftest.py b/server/jupyter_server/tests/extension/conftest.py deleted file mode 100644 index af7b714..0000000 --- a/server/jupyter_server/tests/extension/conftest.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest - -from .mockextensions.app import MockExtensionApp - - -mock_html = """ - - - - - {% block title %}Jupyter Server 1{% endblock %} - - - {% block meta %} - {% endblock %} - - -
    - {% block site %} - {% endblock site %} -
    - {% block after_site %} - {% endblock after_site %} - - -""" - - -@pytest.fixture -def mock_template(jp_template_dir): - index = jp_template_dir.joinpath("index.html") - index.write_text(mock_html) - - -@pytest.fixture -def extension_manager(jp_serverapp): - return jp_serverapp.extension_manager - - -@pytest.fixture -def config_file(jp_config_dir): - """""" - f = jp_config_dir.joinpath("jupyter_mockextension_config.py") - f.write_text("c.MockExtensionApp.mock_trait ='config from file'") - return f - - -@pytest.fixture(autouse=True) -def jp_mockextension_cleanup(): - yield - MockExtensionApp.clear_instance() diff --git a/server/jupyter_server/tests/extension/mockextensions/__init__.py b/server/jupyter_server/tests/extension/mockextensions/__init__.py deleted file mode 100644 index 7b60ae5..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""A mock extension module with a list of extensions -to load in various tests. -""" -from .app import MockExtensionApp - - -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_points(): - return [ - { - "module": "jupyter_server.tests.extension.mockextensions.app", - "app": MockExtensionApp, - }, - {"module": "jupyter_server.tests.extension.mockextensions.mock1"}, - {"module": "jupyter_server.tests.extension.mockextensions.mock2"}, - {"module": "jupyter_server.tests.extension.mockextensions.mock3"}, - ] diff --git a/server/jupyter_server/tests/extension/mockextensions/app.py b/server/jupyter_server/tests/extension/mockextensions/app.py deleted file mode 100644 index 7045417..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/app.py +++ /dev/null @@ -1,55 +0,0 @@ -import os - -from traitlets import List -from traitlets import Unicode - -from jupyter_server.base.handlers import JupyterHandler -from jupyter_server.extension.application import ExtensionApp -from jupyter_server.extension.application import ExtensionAppJinjaMixin -from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin -from jupyter_server.extension.handler import ExtensionHandlerMixin - -STATIC_PATH = os.path.join(os.path.dirname(__file__), "static") - -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_points(): - return [{"module": __name__, "app": MockExtensionApp}] - - -class MockExtensionHandler(ExtensionHandlerMixin, JupyterHandler): - def get(self): - self.finish(self.config.mock_trait) - - -class MockExtensionTemplateHandler( - ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler -): - def get(self): - self.write(self.render_template("index.html")) - - -class MockExtensionApp(ExtensionAppJinjaMixin, ExtensionApp): - - name = "mockextension" - template_paths = List().tag(config=True) - static_paths = [STATIC_PATH] - mock_trait = Unicode("mock trait", config=True) - loaded = False - - serverapp_config = { - "jpserver_extensions": {"jupyter_server.tests.extension.mockextensions.mock1": True} - } - - @staticmethod - def get_extension_package(): - return "jupyter_server.tests.extension.mockextensions" - - def initialize_handlers(self): - self.handlers.append(("/mock", MockExtensionHandler)) - self.handlers.append(("/mock_template", MockExtensionTemplateHandler)) - self.loaded = True - - -if __name__ == "__main__": - MockExtensionApp.launch_instance() diff --git a/server/jupyter_server/tests/extension/mockextensions/mock1.py b/server/jupyter_server/tests/extension/mockextensions/mock1.py deleted file mode 100644 index 49f6d77..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mock1.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mock1` for testing purposes. -""" -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mock1"}] - - -def _load_jupyter_server_extension(serverapp): - serverapp.mockI = True - serverapp.mock_shared = "I" diff --git a/server/jupyter_server/tests/extension/mockextensions/mock2.py b/server/jupyter_server/tests/extension/mockextensions/mock2.py deleted file mode 100644 index 87b8f45..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mock2.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mock2` for testing purposes. -""" -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mock2"}] - - -def _load_jupyter_server_extension(serverapp): - serverapp.mockII = True - serverapp.mock_shared = "II" diff --git a/server/jupyter_server/tests/extension/mockextensions/mock3.py b/server/jupyter_server/tests/extension/mockextensions/mock3.py deleted file mode 100644 index cdbffef..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mock3.py +++ /dev/null @@ -1,6 +0,0 @@ -"""A mock extension named `mock3` for testing purposes. -""" - - -def _load_jupyter_server_extension(serverapp): - pass diff --git a/server/jupyter_server/tests/extension/mockextensions/mockext_both.py b/server/jupyter_server/tests/extension/mockextensions/mockext_both.py deleted file mode 100644 index 38076e5..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mockext_both.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mockext_both` for testing purposes. -""" -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mockext_both"}] - - -def _load_jupyter_server_extension(serverapp): - pass diff --git a/server/jupyter_server/tests/extension/mockextensions/mockext_py.py b/server/jupyter_server/tests/extension/mockextensions/mockext_py.py deleted file mode 100644 index d0cf69b..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mockext_py.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mockext_py` for testing purposes. -""" -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mockext_py"}] - - -def _load_jupyter_server_extension(serverapp): - pass diff --git a/server/jupyter_server/tests/extension/mockextensions/mockext_sys.py b/server/jupyter_server/tests/extension/mockextensions/mockext_sys.py deleted file mode 100644 index 70506e2..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mockext_sys.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mockext_py` for testing purposes. -""" -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mockext_sys"}] - - -def _load_jupyter_server_extension(serverapp): - pass diff --git a/server/jupyter_server/tests/extension/mockextensions/mockext_user.py b/server/jupyter_server/tests/extension/mockextensions/mockext_user.py deleted file mode 100644 index c1e8eaf..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/mockext_user.py +++ /dev/null @@ -1,10 +0,0 @@ -"""A mock extension named `mockext_user` for testing purposes. -""" -# Function that makes these extensions discoverable -# by the test functions. -def _jupyter_server_extension_paths(): - return [{"module": "jupyter_server.tests.extension.mockextensions.mockext_user"}] - - -def _load_jupyter_server_extension(serverapp): - pass diff --git a/server/jupyter_server/tests/extension/mockextensions/static/mock.txt b/server/jupyter_server/tests/extension/mockextensions/static/mock.txt deleted file mode 100644 index 36dd88b..0000000 --- a/server/jupyter_server/tests/extension/mockextensions/static/mock.txt +++ /dev/null @@ -1 +0,0 @@ -mock static content diff --git a/server/jupyter_server/tests/extension/test_app.py b/server/jupyter_server/tests/extension/test_app.py deleted file mode 100644 index 5078a5c..0000000 --- a/server/jupyter_server/tests/extension/test_app.py +++ /dev/null @@ -1,158 +0,0 @@ -import pytest -from traitlets.config import Config - -from .mockextensions.app import MockExtensionApp -from jupyter_server.serverapp import ServerApp -from jupyter_server.utils import run_sync - - -@pytest.fixture -def jp_server_config(jp_template_dir): - config = { - "ServerApp": { - "jpserver_extensions": {"jupyter_server.tests.extension.mockextensions": True}, - }, - "MockExtensionApp": { - "template_paths": [str(jp_template_dir)], - "log_level": "DEBUG", - }, - } - return config - - -@pytest.fixture -def mock_extension(extension_manager): - name = "jupyter_server.tests.extension.mockextensions" - pkg = extension_manager.extensions[name] - point = pkg.extension_points["mockextension"] - app = point.app - return app - - -def test_initialize(jp_serverapp, jp_template_dir, mock_extension): - # Check that settings and handlers were added to the mock extension. - assert isinstance(mock_extension.serverapp, ServerApp) - assert len(mock_extension.handlers) > 0 - assert mock_extension.loaded - assert mock_extension.template_paths == [str(jp_template_dir)] - - -@pytest.mark.parametrize( - "trait_name, trait_value, jp_argv", - ( - [ - "mock_trait", - "test mock trait", - ["--MockExtensionApp.mock_trait=test mock trait"], - ], - ), -) -def test_instance_creation_with_argv( - trait_name, - trait_value, - jp_argv, - mock_extension, -): - assert getattr(mock_extension, trait_name) == trait_value - - -def test_extensionapp_load_config_file( - config_file, - jp_serverapp, - mock_extension, -): - # Assert default config_file_paths is the same in the app and extension. - assert mock_extension.config_file_paths == jp_serverapp.config_file_paths - assert mock_extension.config_dir == jp_serverapp.config_dir - assert mock_extension.config_file_name == "jupyter_mockextension_config" - # Assert that the trait is updated by config file - assert mock_extension.mock_trait == "config from file" - - -OPEN_BROWSER_COMBINATIONS = ( - (True, {}), - (True, {"ServerApp": {"open_browser": True}}), - (False, {"ServerApp": {"open_browser": False}}), - (True, {"MockExtensionApp": {"open_browser": True}}), - (False, {"MockExtensionApp": {"open_browser": False}}), - ( - True, - { - "ServerApp": {"open_browser": True}, - "MockExtensionApp": {"open_browser": True}, - }, - ), - ( - False, - { - "ServerApp": {"open_browser": True}, - "MockExtensionApp": {"open_browser": False}, - }, - ), - ( - True, - { - "ServerApp": {"open_browser": False}, - "MockExtensionApp": {"open_browser": True}, - }, - ), - ( - False, - { - "ServerApp": {"open_browser": False}, - "MockExtensionApp": {"open_browser": False}, - }, - ), -) - - -@pytest.mark.parametrize("expected_value, config", OPEN_BROWSER_COMBINATIONS) -def test_browser_open(monkeypatch, jp_environ, config, expected_value): - serverapp = MockExtensionApp.initialize_server(config=Config(config)) - assert serverapp.open_browser == expected_value - - -def test_load_parallel_extensions(monkeypatch, jp_environ): - serverapp = MockExtensionApp.initialize_server() - exts = serverapp.extension_manager.extensions - assert "jupyter_server.tests.extension.mockextensions.mock1" in exts - assert "jupyter_server.tests.extension.mockextensions" in exts - - exts = serverapp.jpserver_extensions - assert exts["jupyter_server.tests.extension.mockextensions.mock1"] - assert exts["jupyter_server.tests.extension.mockextensions"] - - -def test_stop_extension(jp_serverapp, caplog): - """Test the stop_extension method. - - This should be fired by ServerApp.cleanup_extensions. - """ - calls = 0 - - # load extensions (make sure we only have the one extension loaded - jp_serverapp.extension_manager.load_all_extensions() - extension_name = "jupyter_server.tests.extension.mockextensions" - assert list(jp_serverapp.extension_manager.extension_apps) == [extension_name] - - # add a stop_extension method for the extension app - async def _stop(*args): - nonlocal calls - calls += 1 - - for apps in jp_serverapp.extension_manager.extension_apps.values(): - for app in apps: - if app: - app.stop_extension = _stop - - # call cleanup_extensions, check the logging is correct - caplog.clear() - run_sync(jp_serverapp.cleanup_extensions()) - assert [msg for *_, msg in caplog.record_tuples] == [ - "Shutting down 1 extension", - '{} | extension app "mockextension" stopping'.format(extension_name), - '{} | extension app "mockextension" stopped'.format(extension_name), - ] - - # check the shutdown method was called once - assert calls == 1 diff --git a/server/jupyter_server/tests/extension/test_config.py b/server/jupyter_server/tests/extension/test_config.py deleted file mode 100644 index 8669697..0000000 --- a/server/jupyter_server/tests/extension/test_config.py +++ /dev/null @@ -1,60 +0,0 @@ -import pytest -from jupyter_core.paths import jupyter_config_path - -from jupyter_server.extension.config import ( - ExtensionConfigManager, -) - -# Use ServerApps environment because it monkeypatches -# jupyter_core.paths and provides a config directory -# that's not cross contaminating the user config directory. -pytestmark = pytest.mark.usefixtures("jp_environ") - - -@pytest.fixture -def configd(jp_env_config_path): - """A pathlib.Path object that acts like a jupyter_server_config.d folder.""" - configd = jp_env_config_path.joinpath("jupyter_server_config.d") - configd.mkdir() - return configd - - -ext1_json_config = """\ -{ - "ServerApp": { - "jpserver_extensions": { - "ext1_config": true - } - } -} -""" - - -@pytest.fixture -def ext1_config(configd): - config = configd.joinpath("ext1_config.json") - config.write_text(ext1_json_config) - - -ext2_json_config = """\ -{ - "ServerApp": { - "jpserver_extensions": { - "ext2_config": false - } - } -} -""" - - -@pytest.fixture -def ext2_config(configd): - config = configd.joinpath("ext2_config.json") - config.write_text(ext2_json_config) - - -def test_list_extension_from_configd(ext1_config, ext2_config): - manager = ExtensionConfigManager(read_config_path=jupyter_config_path()) - extensions = manager.get_jpserver_extensions() - assert "ext2_config" in extensions - assert "ext1_config" in extensions diff --git a/server/jupyter_server/tests/extension/test_entrypoint.py b/server/jupyter_server/tests/extension/test_entrypoint.py deleted file mode 100644 index 5f7d10d..0000000 --- a/server/jupyter_server/tests/extension/test_entrypoint.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest - - -# All test coroutines will be treated as marked. -pytestmark = pytest.mark.script_launch_mode("subprocess") - - -def test_server_extension_list(jp_environ, script_runner): - ret = script_runner.run( - "jupyter", - "server", - "extension", - "list", - ) - assert ret.success diff --git a/server/jupyter_server/tests/extension/test_handler.py b/server/jupyter_server/tests/extension/test_handler.py deleted file mode 100644 index d920c66..0000000 --- a/server/jupyter_server/tests/extension/test_handler.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest - - -@pytest.fixture -def jp_server_config(jp_template_dir): - return { - "ServerApp": { - "jpserver_extensions": {"jupyter_server.tests.extension.mockextensions": True} - }, - "MockExtensionApp": {"template_paths": [str(jp_template_dir)]}, - } - - -async def test_handler(jp_fetch): - r = await jp_fetch("https://github.com/mock", method="GET") - assert r.code == 200 - assert r.body.decode() == "mock trait" - - -async def test_handler_template(jp_fetch, mock_template): - r = await jp_fetch("https://github.com/mock_template", method="GET") - assert r.code == 200 - - -@pytest.mark.parametrize( - "jp_server_config", - [ - { - "ServerApp": { - "jpserver_extensions": {"jupyter_server.tests.extension.mockextensions": True} - }, - "MockExtensionApp": { - # Change a trait in the MockExtensionApp using - # the following config value. - "mock_trait": "test mock trait" - }, - } - ], -) -async def test_handler_setting(jp_fetch, jp_server_config): - # Test that the extension trait was picked up by the webapp. - r = await jp_fetch("https://github.com/mock", method="GET") - assert r.code == 200 - assert r.body.decode() == "test mock trait" - - -@pytest.mark.parametrize("jp_argv", (["--MockExtensionApp.mock_trait=test mock trait"],)) -async def test_handler_argv(jp_fetch, jp_argv): - # Test that the extension trait was picked up by the webapp. - r = await jp_fetch("https://github.com/mock", method="GET") - assert r.code == 200 - assert r.body.decode() == "test mock trait" - - -@pytest.mark.parametrize( - "jp_server_config,jp_base_url", - [ - ( - { - "ServerApp": { - "jpserver_extensions": {"jupyter_server.tests.extension.mockextensions": True}, - # Move extension handlers behind a url prefix - "base_url": "test_prefix", - }, - "MockExtensionApp": { - # Change a trait in the MockExtensionApp using - # the following config value. - "mock_trait": "test mock trait" - }, - }, - "/test_prefix/", - ) - ], -) -async def test_base_url(https://github.com/jp_fetch,%20jp_server_config,%20jp_base_url): - # Test that the extension's handlers were properly prefixed - r = await jp_fetch("https://github.com/mock", method="GET") - assert r.code == 200 - assert r.body.decode() == "test mock trait" - - # Test that the static namespace was prefixed by base_url - r = await jp_fetch("https://github.com/static", "mockextension", "mock.txt", method="GET") - assert r.code == 200 - body = r.body.decode() - assert "mock static content" in body diff --git a/server/jupyter_server/tests/extension/test_launch.py b/server/jupyter_server/tests/extension/test_launch.py deleted file mode 100644 index e5cc12e..0000000 --- a/server/jupyter_server/tests/extension/test_launch.py +++ /dev/null @@ -1,111 +0,0 @@ -"""Test launching Jupyter Server Applications -through as ExtensionApp launch_instance. -""" -import os -import subprocess -import sys -import time -from binascii import hexlify -from pathlib import Path - -import pytest -import requests - - -HERE = os.path.dirname(os.path.abspath(__file__)) - - -@pytest.fixture -def port(): - return 9999 - - -@pytest.fixture -def token(): - return hexlify(os.urandom(4)).decode("ascii") - - -@pytest.fixture -def auth_header(token): - return {"Authorization": "token %s" % token} - - -def wait_up(url, interval=0.1, check=None): - while True: - try: - r = requests.get(url) - except Exception: - if check: - assert check() - # print("waiting for %s" % url) - time.sleep(interval) - else: - break - - -@pytest.fixture -def launch_instance(request, port, token): - def _run_in_subprocess(argv=[], add_token=True): - def _kill_extension_app(): - try: - process.terminate() - except OSError: - # Already dead. - pass - process.wait(10) - - if add_token: - f'--ServerApp.token="{token}"', - - process = subprocess.Popen( - [ - sys.executable, - "-m", - "mockextensions.app", - f"--port={port}", - "--ip=127.0.0.1", - "--no-browser", - *argv, - ], - cwd=HERE, - ) - - request.addfinalizer(_kill_extension_app) - url = f"http://127.0.0.1:{port}" - wait_up(url, check=lambda: process.poll() is None) - return process - - return _run_in_subprocess - - -@pytest.fixture -def fetch(port, auth_header): - def _get(endpoint): - url = f"http://127.0.0.1:{port}" + endpoint - return requests.get(url, headers=auth_header) - - return _get - - -def test_launch_instance(launch_instance, fetch): - launch_instance() - r = fetch("https://github.com/mock") - assert r.status_code == 200 - - -def test_base_url(https://github.com/launch_instance,%20fetch): - launch_instance(["--ServerApp.base_url=/foo"]) - r = fetch("https://github.com/foo/mock") - assert r.status_code == 200 - - -def test_token_file(launch_instance, fetch, token): - token_file = HERE / Path("token_file.txt") - os.environ["JUPYTER_TOKEN_FILE"] = str(token_file) - token_file.write_text(token, encoding="utf-8") - - launch_instance(add_token=False) - r = fetch("https://github.com/mock") - del os.environ["JUPYTER_TOKEN_FILE"] - token_file.unlink() - assert r.status_code == 200 diff --git a/server/jupyter_server/tests/extension/test_manager.py b/server/jupyter_server/tests/extension/test_manager.py deleted file mode 100644 index 148b6ea..0000000 --- a/server/jupyter_server/tests/extension/test_manager.py +++ /dev/null @@ -1,132 +0,0 @@ -import os -import unittest.mock as mock - -import pytest -from jupyter_core.paths import jupyter_config_path - -from jupyter_server.extension.manager import ExtensionManager -from jupyter_server.extension.manager import ExtensionMetadataError -from jupyter_server.extension.manager import ExtensionModuleNotFound -from jupyter_server.extension.manager import ExtensionPackage -from jupyter_server.extension.manager import ExtensionPoint - -# Use ServerApps environment because it monkeypatches -# jupyter_core.paths and provides a config directory -# that's not cross contaminating the user config directory. -pytestmark = pytest.mark.usefixtures("jp_environ") - - -def test_extension_point_api(): - # Import mock extension metadata - from .mockextensions import _jupyter_server_extension_points - - # Testing the first path (which is an extension app). - metadata_list = _jupyter_server_extension_points() - point = metadata_list[0] - - module = point["module"] - app = point["app"] - - e = ExtensionPoint(metadata=point) - assert e.module_name == module - assert e.name == app.name - assert app is not None - assert callable(e.load) - assert callable(e.link) - assert e.validate() - - -def test_extension_point_metadata_error(): - # Missing the "module" key. - bad_metadata = {"name": "nonexistent"} - with pytest.raises(ExtensionMetadataError): - ExtensionPoint(metadata=bad_metadata) - - -def test_extension_point_notfound_error(): - bad_metadata = {"module": "nonexistent"} - with pytest.raises(ExtensionModuleNotFound): - ExtensionPoint(metadata=bad_metadata) - - -def test_extension_package_api(): - # Import mock extension metadata - from .mockextensions import _jupyter_server_extension_points - - # Testing the first path (which is an extension app). - metadata_list = _jupyter_server_extension_points() - path1 = metadata_list[0] - app = path1["app"] - - e = ExtensionPackage(name="jupyter_server.tests.extension.mockextensions") - e.extension_points - assert hasattr(e, "extension_points") - assert len(e.extension_points) == len(metadata_list) - assert app.name in e.extension_points - assert e.validate() - - -def test_extension_package_notfound_error(): - with pytest.raises(ExtensionModuleNotFound): - ExtensionPackage(name="nonexistent") - - -def _normalize_path(path_list): - return [p.rstrip(os.path.sep) for p in path_list] - - -def test_extension_manager_api(jp_serverapp): - jpserver_extensions = {"jupyter_server.tests.extension.mockextensions": True} - manager = ExtensionManager(serverapp=jp_serverapp) - assert manager.config_manager - expected = _normalize_path(os.path.join(jupyter_config_path()[0], "serverconfig")) - assert _normalize_path(manager.config_manager.read_config_path[0]) == expected - manager.from_jpserver_extensions(jpserver_extensions) - assert len(manager.extensions) == 1 - assert "jupyter_server.tests.extension.mockextensions" in manager.extensions - - -def test_extension_manager_linked_extensions(jp_serverapp): - name = "jupyter_server.tests.extension.mockextensions" - manager = ExtensionManager(serverapp=jp_serverapp) - manager.add_extension(name, enabled=True) - manager.link_extension(name) - assert name in manager.linked_extensions - - -def test_extension_manager_fail_add(jp_serverapp): - name = "jupyter_server.tests.extension.notanextension" - manager = ExtensionManager(serverapp=jp_serverapp) - manager.add_extension(name, enabled=True) # should only warn - jp_serverapp.reraise_server_extension_failures = True - with pytest.raises(ExtensionModuleNotFound): - manager.add_extension(name, enabled=True) - - -def test_extension_manager_fail_link(jp_serverapp): - name = "jupyter_server.tests.extension.mockextensions.app" - with mock.patch( - "jupyter_server.tests.extension.mockextensions.app.MockExtensionApp.parse_command_line", - side_effect=RuntimeError, - ): - manager = ExtensionManager(serverapp=jp_serverapp) - manager.add_extension(name, enabled=True) - manager.link_extension(name) # should only warn - jp_serverapp.reraise_server_extension_failures = True - with pytest.raises(RuntimeError): - manager.link_extension(name) - - -def test_extension_manager_fail_load(jp_serverapp): - name = "jupyter_server.tests.extension.mockextensions.app" - with mock.patch( - "jupyter_server.tests.extension.mockextensions.app.MockExtensionApp.initialize_handlers", - side_effect=RuntimeError, - ): - manager = ExtensionManager(serverapp=jp_serverapp) - manager.add_extension(name, enabled=True) - manager.link_extension(name) - manager.load_extension(name) # should only warn - jp_serverapp.reraise_server_extension_failures = True - with pytest.raises(RuntimeError): - manager.load_extension(name) diff --git a/server/jupyter_server/tests/extension/test_serverextension.py b/server/jupyter_server/tests/extension/test_serverextension.py deleted file mode 100644 index 5140cdf..0000000 --- a/server/jupyter_server/tests/extension/test_serverextension.py +++ /dev/null @@ -1,106 +0,0 @@ -from collections import OrderedDict - -import pytest -from traitlets.tests.utils import check_help_all_output - -from jupyter_server.config_manager import BaseJSONConfigManager -from jupyter_server.extension.serverextension import _get_config_dir -from jupyter_server.extension.serverextension import toggle_server_extension_python - - -# Use ServerApps environment because it monkeypatches -# jupyter_core.paths and provides a config directory -# that's not cross contaminating the user config directory. -pytestmark = pytest.mark.usefixtures("jp_environ") - - -def test_help_output(): - check_help_all_output("jupyter_server.extension.serverextension") - check_help_all_output("jupyter_server.extension.serverextension", ["enable"]) - check_help_all_output("jupyter_server.extension.serverextension", ["disable"]) - check_help_all_output("jupyter_server.extension.serverextension", ["install"]) - check_help_all_output("jupyter_server.extension.serverextension", ["uninstall"]) - - -def get_config(sys_prefix=True): - cm = BaseJSONConfigManager(config_dir=_get_config_dir(sys_prefix=sys_prefix)) - data = cm.get("jupyter_server_config") - return data.get("ServerApp", {}).get("jpserver_extensions", {}) - - -def test_enable(jp_env_config_path, jp_extension_environ): - toggle_server_extension_python("mock1", True) - config = get_config() - assert config["mock1"] - - -def test_disable(jp_env_config_path, jp_extension_environ): - toggle_server_extension_python("mock1", True) - toggle_server_extension_python("mock1", False) - - config = get_config() - assert not config["mock1"] - - -def test_merge_config(jp_env_config_path, jp_configurable_serverapp, jp_extension_environ): - # Toggle each extension module with a JSON config file - # at the sys-prefix config dir. - toggle_server_extension_python( - "jupyter_server.tests.extension.mockextensions.mockext_sys", - enabled=True, - sys_prefix=True, - ) - toggle_server_extension_python( - "jupyter_server.tests.extension.mockextensions.mockext_user", - enabled=True, - user=True, - ) - - # Write this configuration in two places, sys-prefix and user. - # sys-prefix supercedes users, so the extension should be disabled - # when these two configs merge. - toggle_server_extension_python( - "jupyter_server.tests.extension.mockextensions.mockext_both", - enabled=True, - sys_prefix=True, - ) - toggle_server_extension_python( - "jupyter_server.tests.extension.mockextensions.mockext_both", - enabled=False, - user=True, - ) - - arg = "--ServerApp.jpserver_extensions={{'{mockext_py}': True}}".format( - mockext_py="jupyter_server.tests.extension.mockextensions.mockext_py" - ) - - # Enable the last extension, mockext_py, using the CLI interface. - app = jp_configurable_serverapp(config_dir=str(jp_env_config_path), argv=[arg]) - # Verify that extensions are enabled and merged in proper order. - extensions = app.jpserver_extensions - assert extensions["jupyter_server.tests.extension.mockextensions.mockext_user"] - assert extensions["jupyter_server.tests.extension.mockextensions.mockext_sys"] - assert extensions["jupyter_server.tests.extension.mockextensions.mockext_py"] - # Merging should causes this extension to be disabled. - assert not extensions["jupyter_server.tests.extension.mockextensions.mockext_both"] - - -@pytest.mark.parametrize( - "jp_server_config", - [ - { - "ServerApp": { - "jpserver_extensions": OrderedDict( - [ - ("jupyter_server.tests.extension.mockextensions.mock2", True), - ("jupyter_server.tests.extension.mockextensions.mock1", True), - ] - ) - } - } - ], -) -def test_load_ordered(jp_serverapp, jp_server_config): - assert jp_serverapp.mockII is True, "Mock II should have been loaded" - assert jp_serverapp.mockI is True, "Mock I should have been loaded" - assert jp_serverapp.mock_shared == "II", "Mock II should be loaded after Mock I" diff --git a/server/jupyter_server/tests/extension/test_utils.py b/server/jupyter_server/tests/extension/test_utils.py deleted file mode 100644 index 425b6ba..0000000 --- a/server/jupyter_server/tests/extension/test_utils.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest - -from jupyter_server.extension.utils import validate_extension - - -# Use ServerApps environment because it monkeypatches -# jupyter_core.paths and provides a config directory -# that's not cross contaminating the user config directory. -pytestmark = pytest.mark.usefixtures("jp_environ") - - -def test_validate_extension(): - # enabled at sys level - assert validate_extension("jupyter_server.tests.extension.mockextensions.mockext_sys") - # enabled at sys, disabled at user - assert validate_extension("jupyter_server.tests.extension.mockextensions.mockext_both") - # enabled at user - assert validate_extension("jupyter_server.tests.extension.mockextensions.mockext_user") - # enabled at Python - assert validate_extension("jupyter_server.tests.extension.mockextensions.mockext_py") diff --git a/server/jupyter_server/tests/namespace-package-test/README.md b/server/jupyter_server/tests/namespace-package-test/README.md deleted file mode 100644 index f72158b..0000000 --- a/server/jupyter_server/tests/namespace-package-test/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Blank namespace package for use in testing. - -https://www.python.org/dev/peps/pep-0420/ diff --git a/server/jupyter_server/tests/namespace-package-test/setup.cfg b/server/jupyter_server/tests/namespace-package-test/setup.cfg deleted file mode 100644 index 105be78..0000000 --- a/server/jupyter_server/tests/namespace-package-test/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[metadata] -name = namespace-package-test - -[options] -packages = find_namespace: diff --git a/server/jupyter_server/tests/namespace-package-test/test_namespace/test_package/__init__.py b/server/jupyter_server/tests/namespace-package-test/test_namespace/test_package/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/nbconvert/__init__.py b/server/jupyter_server/tests/nbconvert/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/nbconvert/test_handlers.py b/server/jupyter_server/tests/nbconvert/test_handlers.py deleted file mode 100644 index 75d2372..0000000 --- a/server/jupyter_server/tests/nbconvert/test_handlers.py +++ /dev/null @@ -1,150 +0,0 @@ -# coding: utf-8 -import json -from base64 import encodebytes -from shutil import which - -import pytest -import tornado -from nbformat import writes -from nbformat.v4 import new_code_cell -from nbformat.v4 import new_markdown_cell -from nbformat.v4 import new_notebook -from nbformat.v4 import new_output - -from ..utils import expected_http_error - - -png_green_pixel = encodebytes( - b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00" - b"\x00\x00\x01\x00\x00x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT" - b"\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82" -).decode("ascii") - - -@pytest.fixture -def notebook(jp_root_dir): - # Build sub directory. - subdir = jp_root_dir / "foo" - if not jp_root_dir.joinpath("foo").is_dir(): - subdir.mkdir() - - # Build a notebook programmatically. - nb = new_notebook() - nb.cells.append(new_markdown_cell("Created by test Âŗ")) - cc1 = new_code_cell(source="print(2*6)") - cc1.outputs.append(new_output(output_type="stream", text="12")) - cc1.outputs.append( - new_output( - output_type="execute_result", - data={"image/png": png_green_pixel}, - execution_count=1, - ) - ) - nb.cells.append(cc1) - - # Write file to tmp dir. - nbfile = subdir / "testnb.ipynb" - nbfile.write_text(writes(nb, version=4), encoding="utf-8") - - -pytestmark = pytest.mark.skipif(not which("pandoc"), reason="Command 'pandoc' is not available") - - -async def test_from_file(jp_fetch, notebook): - r = await jp_fetch( - "nbconvert", - "html", - "foo", - "testnb.ipynb", - method="GET", - params={"download": False}, - ) - - assert r.code == 200 - assert "text/html" in r.headers["Content-Type"] - assert "Created by test" in r.body.decode() - assert "print" in r.body.decode() - - r = await jp_fetch( - "nbconvert", - "python", - "foo", - "testnb.ipynb", - method="GET", - params={"download": False}, - ) - - assert r.code == 200 - assert "text/x-python" in r.headers["Content-Type"] - assert "print(2*6)" in r.body.decode() - - -async def test_from_file_404(jp_fetch, notebook): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "nbconvert", - "html", - "foo", - "thisdoesntexist.ipynb", - method="GET", - params={"download": False}, - ) - assert expected_http_error(e, 404) - - -async def test_from_file_download(jp_fetch, notebook): - r = await jp_fetch( - "nbconvert", - "python", - "foo", - "testnb.ipynb", - method="GET", - params={"download": True}, - ) - content_disposition = r.headers["Content-Disposition"] - assert "attachment" in content_disposition - assert "testnb.py" in content_disposition - - -async def test_from_file_zip(jp_fetch, notebook): - r = await jp_fetch( - "nbconvert", - "latex", - "foo", - "testnb.ipynb", - method="GET", - params={"download": True}, - ) - assert "application/zip" in r.headers["Content-Type"] - assert ".zip" in r.headers["Content-Disposition"] - - -async def test_from_post(jp_fetch, notebook): - r = await jp_fetch( - "api/contents/foo/testnb.ipynb", - method="GET", - ) - nbmodel = json.loads(r.body.decode()) - - r = await jp_fetch("https://github.com/nbconvert", "html", method="POST", body=json.dumps(nbmodel)) - assert r.code == 200 - assert "text/html" in r.headers["Content-Type"] - assert "Created by test" in r.body.decode() - assert "print" in r.body.decode() - - r = await jp_fetch("https://github.com/nbconvert", "python", method="POST", body=json.dumps(nbmodel)) - assert r.code == 200 - assert "text/x-python" in r.headers["Content-Type"] - assert "print(2*6)" in r.body.decode() - - -async def test_from_post_zip(jp_fetch, notebook): - r = await jp_fetch( - "api/contents/foo/testnb.ipynb", - method="GET", - ) - nbmodel = json.loads(r.body.decode()) - - r = await jp_fetch("https://github.com/nbconvert", "latex", method="POST", body=json.dumps(nbmodel)) - assert "application/zip" in r.headers["Content-Type"] - assert ".zip" in r.headers["Content-Disposition"] diff --git a/server/jupyter_server/tests/services/__init__.py b/server/jupyter_server/tests/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/api/__init__.py b/server/jupyter_server/tests/services/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/api/test_api.py b/server/jupyter_server/tests/services/api/test_api.py deleted file mode 100644 index c1620ff..0000000 --- a/server/jupyter_server/tests/services/api/test_api.py +++ /dev/null @@ -1,23 +0,0 @@ -import json - - -async def test_get_spec(jp_fetch): - response = await jp_fetch("https://github.com/api", "spec.yaml", method="GET") - assert response.code == 200 - - -async def test_get_status(jp_fetch): - response = await jp_fetch("https://github.com/api", "status", method="GET") - assert response.code == 200 - assert response.headers.get("Content-Type") == "application/json" - status = json.loads(response.body.decode("utf8")) - assert sorted(status.keys()) == [ - "connections", - "kernels", - "last_activity", - "started", - ] - assert status["connections"] == 0 - assert status["kernels"] == 0 - assert status["last_activity"].endswith("Z") - assert status["started"].endswith("Z") diff --git a/server/jupyter_server/tests/services/config/__init__.py b/server/jupyter_server/tests/services/config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/config/test_api.py b/server/jupyter_server/tests/services/config/test_api.py deleted file mode 100644 index 9d4a4b2..0000000 --- a/server/jupyter_server/tests/services/config/test_api.py +++ /dev/null @@ -1,50 +0,0 @@ -import json - - -async def test_create_retrieve_config(jp_fetch): - sample = {"foo": "bar", "baz": 73} - response = await jp_fetch("https://github.com/api", "config", "example", method="PUT", body=json.dumps(sample)) - assert response.code == 204 - - response2 = await jp_fetch( - "api", - "config", - "example", - method="GET", - ) - assert response2.code == 200 - assert json.loads(response2.body.decode()) == sample - - -async def test_modify(jp_fetch): - sample = {"foo": "bar", "baz": 73, "sub": {"a": 6, "b": 7}, "sub2": {"c": 8}} - - modified_sample = { - "foo": None, # should delete foo - "baz": 75, - "wib": [1, 2, 3], - "sub": {"a": 8, "b": None, "d": 9}, - "sub2": {"c": None}, # should delete sub2 - } - - diff = {"baz": 75, "wib": [1, 2, 3], "sub": {"a": 8, "d": 9}} - - await jp_fetch("https://github.com/api", "config", "example", method="PUT", body=json.dumps(sample)) - - response2 = await jp_fetch( - "api", "config", "example", method="PATCH", body=json.dumps(modified_sample) - ) - - assert response2.code == 200 - assert json.loads(response2.body.decode()) == diff - - -async def test_get_unknown(jp_fetch): - response = await jp_fetch( - "api", - "config", - "nonexistant", - method="GET", - ) - assert response.code == 200 - assert json.loads(response.body.decode()) == {} diff --git a/server/jupyter_server/tests/services/contents/__init__.py b/server/jupyter_server/tests/services/contents/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/contents/test_api.py b/server/jupyter_server/tests/services/contents/test_api.py deleted file mode 100644 index 2d15cc2..0000000 --- a/server/jupyter_server/tests/services/contents/test_api.py +++ /dev/null @@ -1,802 +0,0 @@ -import json -import pathlib -import sys -from base64 import decodebytes -from base64 import encodebytes -from unicodedata import normalize - -import pytest -import tornado -from nbformat import from_dict -from nbformat import writes -from nbformat.v4 import new_markdown_cell -from nbformat.v4 import new_notebook - -from ...utils import expected_http_error -from jupyter_server.utils import url_path_join - - -def notebooks_only(dir_model): - return [nb for nb in dir_model["content"] if nb["type"] == "notebook"] - - -def dirs_only(dir_model): - return [x for x in dir_model["content"] if x["type"] == "directory"] - - -dirs = [ - ("", "inroot"), - ("Directory with spaces in", "inspace"), - ("unicodÊ", "innonascii"), - ("foo", "a"), - ("foo", "b"), - ("foo", "name with spaces"), - ("foo", "unicodÊ"), - ("foo/bar", "baz"), - ("ordering", "A"), - ("ordering", "b"), - ("ordering", "C"), - ("ÃĨ b", "ç d"), -] - - -@pytest.fixture(params=["FileContentsManager", "AsyncFileContentsManager"]) -def jp_argv(request): - return [ - "--ServerApp.contents_manager_class=jupyter_server.services.contents.filemanager." - + request.param - ] - - -@pytest.fixture -def contents_dir(tmp_path, jp_serverapp): - return tmp_path / jp_serverapp.root_dir - - -@pytest.fixture -def contents(contents_dir): - # Create files in temporary directory - paths = { - "notebooks": [], - "textfiles": [], - "blobs": [], - } - for d, name in dirs: - p = contents_dir / d - p.mkdir(parents=True, exist_ok=True) - - # Create a notebook - nb = writes(new_notebook(), version=4) - nbname = p.joinpath("{}.ipynb".format(name)) - nbname.write_text(nb, encoding="utf-8") - paths["notebooks"].append(nbname.relative_to(contents_dir)) - - # Create a text file - txt = "{} text file".format(name) - txtname = p.joinpath("{}.txt".format(name)) - txtname.write_text(txt, encoding="utf-8") - paths["textfiles"].append(txtname.relative_to(contents_dir)) - - # Create a random blob - blob = name.encode("utf-8") + b"\xFF" - blobname = p.joinpath("{}.blob".format(name)) - blobname.write_bytes(blob) - paths["blobs"].append(blobname.relative_to(contents_dir)) - paths["all"] = list(paths.values()) - return paths - - -@pytest.fixture -def folders(): - return list(set(item[0] for item in dirs)) - - -@pytest.mark.parametrize("path,name", dirs) -async def test_list_notebooks(jp_fetch, contents, path, name): - response = await jp_fetch( - "api", - "contents", - path, - method="GET", - ) - data = json.loads(response.body.decode()) - nbs = notebooks_only(data) - assert len(nbs) > 0 - assert name + ".ipynb" in [normalize("NFC", n["name"]) for n in nbs] - assert url_path_join(path, name + ".ipynb") in [normalize("NFC", n["path"]) for n in nbs] - - -@pytest.mark.parametrize("path,name", dirs) -async def test_get_dir_no_contents(jp_fetch, contents, path, name): - response = await jp_fetch( - "api", - "contents", - path, - method="GET", - params=dict( - content="0", - ), - ) - model = json.loads(response.body.decode()) - assert model["path"] == path - assert model["type"] == "directory" - assert "content" in model - assert model["content"] is None - - -async def test_list_nonexistant_dir(jp_fetch, contents): - with pytest.raises(tornado.httpclient.HTTPClientError): - await jp_fetch( - "api", - "contents", - "nonexistant", - method="GET", - ) - - -@pytest.mark.parametrize("path,name", dirs) -async def test_get_nb_contents(jp_fetch, contents, path, name): - nbname = name + ".ipynb" - nbpath = (path + "/" + nbname).lstrip("/") - r = await jp_fetch("https://github.com/api", "contents", nbpath, method="GET", params=dict(content="1")) - model = json.loads(r.body.decode()) - assert model["name"] == nbname - assert model["path"] == nbpath - assert model["type"] == "notebook" - assert "content" in model - assert model["format"] == "json" - assert "metadata" in model["content"] - assert isinstance(model["content"]["metadata"], dict) - - -@pytest.mark.parametrize("path,name", dirs) -async def test_get_nb_no_contents(jp_fetch, contents, path, name): - nbname = name + ".ipynb" - nbpath = (path + "/" + nbname).lstrip("/") - r = await jp_fetch("https://github.com/api", "contents", nbpath, method="GET", params=dict(content="0")) - model = json.loads(r.body.decode()) - assert model["name"] == nbname - assert model["path"] == nbpath - assert model["type"] == "notebook" - assert "content" in model - assert model["content"] is None - - -async def test_get_nb_invalid(contents_dir, jp_fetch, contents): - nb = { - "nbformat": 4, - "metadata": {}, - "cells": [ - { - "cell_type": "wrong", - "metadata": {}, - } - ], - } - nbpath = "ÃĨ b/Validate tÊst.ipynb" - (contents_dir / nbpath).write_text(json.dumps(nb)) - r = await jp_fetch( - "api", - "contents", - nbpath, - method="GET", - ) - model = json.loads(r.body.decode()) - assert model["path"] == nbpath - assert model["type"] == "notebook" - assert "content" in model - assert "message" in model - assert "validation failed" in model["message"].lower() - - -async def test_get_contents_no_such_file(jp_fetch): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "foo/q.ipynb", - method="GET", - ) - assert e.value.code == 404 - - -@pytest.mark.parametrize("path,name", dirs) -async def test_get_text_file_contents(jp_fetch, contents, path, name): - txtname = name + ".txt" - txtpath = (path + "/" + txtname).lstrip("/") - r = await jp_fetch("https://github.com/api", "contents", txtpath, method="GET", params=dict(content="1")) - model = json.loads(r.body.decode()) - assert model["name"] == txtname - assert model["path"] == txtpath - assert "content" in model - assert model["format"] == "text" - assert model["type"] == "file" - assert model["content"] == "{} text file".format(name) - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "foo/q.txt", - method="GET", - ) - assert expected_http_error(e, 404) - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "foo/bar/baz.blob", - method="GET", - params=dict(type="file", format="text"), - ) - assert expected_http_error(e, 400) - - -@pytest.mark.parametrize("path,name", dirs) -async def test_get_binary_file_contents(jp_fetch, contents, path, name): - blobname = name + ".blob" - blobpath = (path + "/" + blobname).lstrip("/") - r = await jp_fetch("https://github.com/api", "contents", blobpath, method="GET", params=dict(content="1")) - model = json.loads(r.body.decode()) - assert model["name"] == blobname - assert model["path"] == blobpath - assert "content" in model - assert model["format"] == "base64" - assert model["type"] == "file" - data_out = decodebytes(model["content"].encode("ascii")) - data_in = name.encode("utf-8") + b"\xFF" - assert data_in == data_out - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "foo/q.txt", - method="GET", - ) - assert expected_http_error(e, 404) - - -async def test_get_bad_type(jp_fetch, contents): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - path = "unicodÊ" - type = "file" - await jp_fetch( - "api", - "contents", - path, - method="GET", - params=dict(type=type), # This should be a directory, and thus throw and error - ) - assert expected_http_error(e, 400, "%s is a directory, not a %s" % (path, type)) - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - path = "unicodÊ/innonascii.ipynb" - type = "directory" - await jp_fetch( - "api", - "contents", - path, - method="GET", - params=dict(type=type), # This should be a file, and thus throw and error - ) - assert expected_http_error(e, 400, "%s is not a directory" % path) - - -@pytest.fixture -def _check_created(jp_base_url): - def _inner(r, contents_dir, path, name, type="notebook"): - fpath = path + "/" + name - assert r.code == 201 - location = jp_base_url + "api/contents/" + tornado.escape.url_escape(fpath, plus=False) - assert r.headers["Location"] == location - model = json.loads(r.body.decode()) - assert model["name"] == name - assert model["path"] == fpath - assert model["type"] == type - path = contents_dir + "/" + fpath - if type == "directory": - assert pathlib.Path(path).is_dir() - else: - assert pathlib.Path(path).is_file() - - return _inner - - -async def test_create_untitled(jp_fetch, contents, contents_dir, _check_created): - path = "ÃĨ b" - name = "Untitled.ipynb" - r = await jp_fetch("https://github.com/api", "contents", path, method="POST", body=json.dumps({"ext": ".ipynb"})) - _check_created(r, str(contents_dir), path, name, type="notebook") - - name = "Untitled1.ipynb" - r = await jp_fetch("https://github.com/api", "contents", path, method="POST", body=json.dumps({"ext": ".ipynb"})) - _check_created(r, str(contents_dir), path, name, type="notebook") - - path = "foo/bar" - name = "Untitled.ipynb" - r = await jp_fetch("https://github.com/api", "contents", path, method="POST", body=json.dumps({"ext": ".ipynb"})) - _check_created(r, str(contents_dir), path, name, type="notebook") - - -async def test_create_untitled_txt(jp_fetch, contents, contents_dir, _check_created): - name = "untitled.txt" - path = "foo/bar" - r = await jp_fetch("https://github.com/api", "contents", path, method="POST", body=json.dumps({"ext": ".txt"})) - _check_created(r, str(contents_dir), path, name, type="file") - - r = await jp_fetch("https://github.com/api", "contents", path, name, method="GET") - model = json.loads(r.body.decode()) - assert model["type"] == "file" - assert model["format"] == "text" - assert model["content"] == "" - - -async def test_upload(jp_fetch, contents, contents_dir, _check_created): - nb = new_notebook() - nbmodel = {"content": nb, "type": "notebook"} - path = "ÃĨ b" - name = "Upload tÊst.ipynb" - r = await jp_fetch("https://github.com/api", "contents", path, name, method="PUT", body=json.dumps(nbmodel)) - _check_created(r, str(contents_dir), path, name) - - -async def test_mkdir_untitled(jp_fetch, contents, contents_dir, _check_created): - name = "Untitled Folder" - path = "ÃĨ b" - r = await jp_fetch( - "api", "contents", path, method="POST", body=json.dumps({"type": "directory"}) - ) - _check_created(r, str(contents_dir), path, name, type="directory") - - name = "Untitled Folder 1" - r = await jp_fetch( - "api", "contents", path, method="POST", body=json.dumps({"type": "directory"}) - ) - _check_created(r, str(contents_dir), path, name, type="directory") - - name = "Untitled Folder" - path = "foo/bar" - r = await jp_fetch( - "api", "contents", path, method="POST", body=json.dumps({"type": "directory"}) - ) - _check_created(r, str(contents_dir), path, name, type="directory") - - -async def test_mkdir(jp_fetch, contents, contents_dir, _check_created): - name = "New ∂ir" - path = "ÃĨ b" - r = await jp_fetch( - "api", - "contents", - path, - name, - method="PUT", - body=json.dumps({"type": "directory"}), - ) - _check_created(r, str(contents_dir), path, name, type="directory") - - -async def test_mkdir_hidden_400(jp_fetch): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "ÃĨ b/.hidden", - method="PUT", - body=json.dumps({"type": "directory"}), - ) - assert expected_http_error(e, 400) - - -async def test_upload_txt(jp_fetch, contents, contents_dir, _check_created): - body = "Ãŧnicode tÊxt" - model = { - "content": body, - "format": "text", - "type": "file", - } - path = "ÃĨ b" - name = "Upload tÊst.txt" - await jp_fetch("https://github.com/api", "contents", path, name, method="PUT", body=json.dumps(model)) - - # check roundtrip - r = await jp_fetch("https://github.com/api", "contents", path, name, method="GET") - model = json.loads(r.body.decode()) - assert model["type"] == "file" - assert model["format"] == "text" - assert model["path"] == path + "/" + name - assert model["content"] == body - - -async def test_upload_b64(jp_fetch, contents, contents_dir, _check_created): - body = b"\xFFblob" - b64body = encodebytes(body).decode("ascii") - model = { - "content": b64body, - "format": "base64", - "type": "file", - } - path = "ÃĨ b" - name = "Upload tÊst.blob" - await jp_fetch("https://github.com/api", "contents", path, name, method="PUT", body=json.dumps(model)) - # check roundtrip - r = await jp_fetch("https://github.com/api", "contents", path, name, method="GET") - model = json.loads(r.body.decode()) - assert model["type"] == "file" - assert model["path"] == path + "/" + name - assert model["format"] == "base64" - decoded = decodebytes(model["content"].encode("ascii")) - assert decoded == body - - -async def test_copy(jp_fetch, contents, contents_dir, _check_created): - path = "ÃĨ b" - name = "ç d.ipynb" - copy = "ç d-Copy1.ipynb" - r = await jp_fetch( - "api", - "contents", - path, - method="POST", - body=json.dumps({"copy_from": path + "/" + name}), - ) - _check_created(r, str(contents_dir), path, copy, type="notebook") - - # Copy the same file name - copy2 = "ç d-Copy2.ipynb" - r = await jp_fetch( - "api", - "contents", - path, - method="POST", - body=json.dumps({"copy_from": path + "/" + name}), - ) - _check_created(r, str(contents_dir), path, copy2, type="notebook") - - # copy a copy. - copy3 = "ç d-Copy3.ipynb" - r = await jp_fetch( - "api", - "contents", - path, - method="POST", - body=json.dumps({"copy_from": path + "/" + copy2}), - ) - _check_created(r, str(contents_dir), path, copy3, type="notebook") - - -async def test_copy_path(jp_fetch, contents, contents_dir, _check_created): - path1 = "foo" - path2 = "ÃĨ b" - name = "a.ipynb" - copy = "a-Copy1.ipynb" - r = await jp_fetch( - "api", - "contents", - path2, - method="POST", - body=json.dumps({"copy_from": path1 + "/" + name}), - ) - _check_created(r, str(contents_dir), path2, name, type="notebook") - - r = await jp_fetch( - "api", - "contents", - path2, - method="POST", - body=json.dumps({"copy_from": path1 + "/" + name}), - ) - _check_created(r, str(contents_dir), path2, copy, type="notebook") - - -async def test_copy_put_400(jp_fetch, contents, contents_dir, _check_created): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "ÃĨ b/cøpy.ipynb", - method="PUT", - body=json.dumps({"copy_from": "ÃĨ b/ç d.ipynb"}), - ) - assert expected_http_error(e, 400) - - -async def test_copy_dir_400(jp_fetch, contents, contents_dir, _check_created): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch( - "api", - "contents", - "foo", - method="POST", - body=json.dumps({"copy_from": "ÃĨ b"}), - ) - assert expected_http_error(e, 400) - - -@pytest.mark.parametrize("path,name", dirs) -async def test_delete(jp_fetch, contents, contents_dir, path, name, _check_created): - nbname = name + ".ipynb" - nbpath = (path + "/" + nbname).lstrip("/") - r = await jp_fetch( - "api", - "contents", - nbpath, - method="DELETE", - ) - assert r.code == 204 - - -async def test_delete_dirs(jp_fetch, contents, folders): - # Iterate over folders - for name in sorted(folders + ["/"], key=len, reverse=True): - r = await jp_fetch("https://github.com/api", "contents", name, method="GET") - # Get JSON blobs for each content. - listing = json.loads(r.body.decode())["content"] - # Delete all content - for model in listing: - await jp_fetch("https://github.com/api", "contents", model["path"], method="DELETE") - # Make sure all content has been deleted. - r = await jp_fetch("https://github.com/api", "contents", method="GET") - model = json.loads(r.body.decode()) - assert model["content"] == [] - - -@pytest.mark.skipif(sys.platform == "win32", reason="Disabled deleting non-empty dirs on Windows") -async def test_delete_non_empty_dir(jp_fetch, contents): - # Delete a folder - await jp_fetch("https://github.com/api", "contents", "ÃĨ b", method="DELETE") - # Check that the folder was been deleted. - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/api", "contents", "ÃĨ b", method="GET") - assert expected_http_error(e, 404) - - -async def test_rename(jp_fetch, jp_base_url, contents, contents_dir): - path = "foo" - name = "a.ipynb" - new_name = "z.ipynb" - # Rename the file - r = await jp_fetch( - "api", - "contents", - path, - name, - method="PATCH", - body=json.dumps({"path": path + "/" + new_name}), - ) - fpath = path + "/" + new_name - assert r.code == 200 - location = url_path_join(jp_base_url, "api/contents/", fpath) - assert r.headers["Location"] == location - model = json.loads(r.body.decode()) - assert model["name"] == new_name - assert model["path"] == fpath - fpath = str(contents_dir / fpath) - assert pathlib.Path(fpath).is_file() - - # Check that the files have changed - r = await jp_fetch("https://github.com/api", "contents", path, method="GET") - listing = json.loads(r.body.decode()) - nbnames = [name["name"] for name in listing["content"]] - assert "z.ipynb" in nbnames - assert "a.ipynb" not in nbnames - - -async def test_checkpoints_follow_file(jp_fetch, contents): - path = "foo" - name = "a.ipynb" - - # Read initial file. - r = await jp_fetch("https://github.com/api", "contents", path, name, method="GET") - model = json.loads(r.body.decode()) - - # Create a checkpoint of initial state - r = await jp_fetch( - "api", - "contents", - path, - name, - "checkpoints", - method="POST", - allow_nonstandard_methods=True, - ) - cp1 = json.loads(r.body.decode()) - - # Modify file and save. - nbcontent = model["content"] - nb = from_dict(nbcontent) - hcell = new_markdown_cell("Created by test") - nb.cells.append(hcell) - nbmodel = {"content": nb, "type": "notebook"} - await jp_fetch("https://github.com/api", "contents", path, name, method="PUT", body=json.dumps(nbmodel)) - - # List checkpoints - r = await jp_fetch( - "api", - "contents", - path, - name, - "checkpoints", - method="GET", - ) - cps = json.loads(r.body.decode()) - assert cps == [cp1] - - r = await jp_fetch("https://github.com/api", "contents", path, name, method="GET") - model = json.loads(r.body.decode()) - nbcontent = model["content"] - nb = from_dict(nbcontent) - assert nb.cells[0].source == "Created by test" - - -async def test_rename_existing(jp_fetch, contents): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - path = "foo" - name = "a.ipynb" - new_name = "b.ipynb" - # Rename the file - await jp_fetch( - "api", - "contents", - path, - name, - method="PATCH", - body=json.dumps({"path": path + "/" + new_name}), - ) - assert expected_http_error(e, 409) - - -async def test_save(jp_fetch, contents): - r = await jp_fetch("https://github.com/api", "contents", "foo/a.ipynb", method="GET") - model = json.loads(r.body.decode()) - nbmodel = model["content"] - nb = from_dict(nbmodel) - nb.cells.append(new_markdown_cell("Created by test Âŗ")) - nbmodel = {"content": nb, "type": "notebook"} - await jp_fetch("https://github.com/api", "contents", "foo/a.ipynb", method="PUT", body=json.dumps(nbmodel)) - # Round trip. - r = await jp_fetch("https://github.com/api", "contents", "foo/a.ipynb", method="GET") - model = json.loads(r.body.decode()) - newnb = from_dict(model["content"]) - assert newnb.cells[0].source == "Created by test Âŗ" - - -async def test_checkpoints(jp_fetch, contents): - path = "foo/a.ipynb" - resp = await jp_fetch("https://github.com/api", "contents", path, method="GET") - model = json.loads(resp.body.decode()) - r = await jp_fetch( - "api", - "contents", - path, - "checkpoints", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 201 - cp1 = json.loads(r.body.decode()) - assert set(cp1) == {"id", "last_modified"} - assert r.headers["Location"].split("/")[-1] == cp1["id"] - - # Modify it. - nbcontent = model["content"] - nb = from_dict(nbcontent) - hcell = new_markdown_cell("Created by test") - nb.cells.append(hcell) - - # Save it. - nbmodel = {"content": nb, "type": "notebook"} - await jp_fetch("https://github.com/api", "contents", path, method="PUT", body=json.dumps(nbmodel)) - - # List checkpoints - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", method="GET") - cps = json.loads(r.body.decode()) - assert cps == [cp1] - - r = await jp_fetch("https://github.com/api", "contents", path, method="GET") - nbcontent = json.loads(r.body.decode())["content"] - nb = from_dict(nbcontent) - assert nb.cells[0].source == "Created by test" - - # Restore Checkpoint cp1 - r = await jp_fetch( - "api", - "contents", - path, - "checkpoints", - cp1["id"], - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 204 - - r = await jp_fetch("https://github.com/api", "contents", path, method="GET") - nbcontent = json.loads(r.body.decode())["content"] - nb = from_dict(nbcontent) - assert nb.cells == [] - - # Delete cp1 - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", cp1["id"], method="DELETE") - assert r.code == 204 - - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", method="GET") - cps = json.loads(r.body.decode()) - assert cps == [] - - -async def test_file_checkpoints(jp_fetch, contents): - path = "foo/a.txt" - resp = await jp_fetch("https://github.com/api", "contents", path, method="GET") - orig_content = json.loads(resp.body.decode())["content"] - r = await jp_fetch( - "api", - "contents", - path, - "checkpoints", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 201 - cp1 = json.loads(r.body.decode()) - assert set(cp1) == {"id", "last_modified"} - assert r.headers["Location"].split("/")[-1] == cp1["id"] - - # Modify it. - new_content = orig_content + "\nsecond line" - model = { - "content": new_content, - "type": "file", - "format": "text", - } - - # Save it. - await jp_fetch("https://github.com/api", "contents", path, method="PUT", body=json.dumps(model)) - - # List checkpoints - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", method="GET") - cps = json.loads(r.body.decode()) - assert cps == [cp1] - - r = await jp_fetch("https://github.com/api", "contents", path, method="GET") - content = json.loads(r.body.decode())["content"] - assert content == new_content - - # Restore Checkpoint cp1 - r = await jp_fetch( - "api", - "contents", - path, - "checkpoints", - cp1["id"], - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 204 - - r = await jp_fetch("https://github.com/api", "contents", path, method="GET") - restored_content = json.loads(r.body.decode())["content"] - assert restored_content == orig_content - - # Delete cp1 - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", cp1["id"], method="DELETE") - assert r.code == 204 - - r = await jp_fetch("https://github.com/api", "contents", path, "checkpoints", method="GET") - cps = json.loads(r.body.decode()) - assert cps == [] - - -async def test_trust(jp_fetch, contents): - # It should be able to trust a notebook that exists - for path in contents["notebooks"]: - r = await jp_fetch( - "api", - "contents", - str(path), - "trust", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 201 diff --git a/server/jupyter_server/tests/services/contents/test_config.py b/server/jupyter_server/tests/services/contents/test_config.py deleted file mode 100644 index 741c10c..0000000 --- a/server/jupyter_server/tests/services/contents/test_config.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest - -from jupyter_server.services.contents.checkpoints import AsyncCheckpoints -from jupyter_server.services.contents.filecheckpoints import AsyncGenericFileCheckpoints -from jupyter_server.services.contents.filecheckpoints import GenericFileCheckpoints -from jupyter_server.services.contents.manager import AsyncContentsManager - - -@pytest.fixture(params=[AsyncGenericFileCheckpoints, GenericFileCheckpoints]) -def jp_server_config(request): - return {"FileContentsManager": {"checkpoints_class": request.param}} - - -def test_config_did_something(jp_server_config, jp_serverapp): - assert isinstance( - jp_serverapp.contents_manager.checkpoints, - jp_server_config["FileContentsManager"]["checkpoints_class"], - ) - - -async def test_async_contents_manager(jp_configurable_serverapp): - config = {"ContentsManager": {"checkpoints_class": AsyncCheckpoints}} - argv = [ - "--ServerApp.contents_manager_class=jupyter_server.services.contents.manager.AsyncContentsManager" - ] - app = jp_configurable_serverapp(config=config, argv=argv) - assert isinstance(app.contents_manager, AsyncContentsManager) diff --git a/server/jupyter_server/tests/services/contents/test_fileio.py b/server/jupyter_server/tests/services/contents/test_fileio.py deleted file mode 100644 index 98f3a31..0000000 --- a/server/jupyter_server/tests/services/contents/test_fileio.py +++ /dev/null @@ -1,139 +0,0 @@ -import functools -import io -import os -import stat -import sys - -import decorator -import pytest -from ipython_genutils.testing.decorators import skip_win32 as _skip_win32 - -from jupyter_server.services.contents.fileio import atomic_writing - - -@functools.wraps(_skip_win32) -def skip_win32(f): - # Patches the "skip_win32" method to allow pytest fixtures - # in methods wrapped by this decorator. - def inner(f, *args, **kwargs): - decorated_f = _skip_win32(f) - return decorated_f(*args, **kwargs) - - return decorator.decorator(inner, f) - - -umask = 0 - - -def test_atomic_writing(tmp_path): - class CustomExc(Exception): - pass - - f1 = tmp_path / "penguin" - f1.write_text("Before") - - if os.name != "nt": - os.chmod(str(f1), 0o701) - orig_mode = stat.S_IMODE(os.stat(str(f1)).st_mode) - - f2 = tmp_path / "flamingo" - try: - os.symlink(str(f1), str(f2)) - have_symlink = True - except (AttributeError, NotImplementedError, OSError): - # AttributeError: Python doesn't support it - # NotImplementedError: The system doesn't support it - # OSError: The user lacks the privilege (Windows) - have_symlink = False - - with pytest.raises(CustomExc): - with atomic_writing(str(f1)) as f: - f.write("Failing write") - raise CustomExc - - with io.open(str(f1), "r") as f: - assert f.read() == "Before" - - with atomic_writing(str(f1)) as f: - f.write("Overwritten") - - with io.open(str(f1), "r") as f: - assert f.read() == "Overwritten" - - if os.name != "nt": - mode = stat.S_IMODE(os.stat(str(f1)).st_mode) - assert mode == orig_mode - - if have_symlink: - # Check that writing over a file preserves a symlink - with atomic_writing(str(f2)) as f: - f.write("written from symlink") - - with io.open(str(f1), "r") as f: - assert f.read() == "written from symlink" - - -@pytest.fixture -def handle_umask(): - global umask - umask = os.umask(0) - os.umask(umask) - yield - os.umask(umask) - - -@pytest.mark.skipif(sys.platform.startswith("win"), reason="Windows") -def test_atomic_writing_umask(handle_umask, tmp_path): - - os.umask(0o022) - f1 = str(tmp_path / "1") - with atomic_writing(f1) as f: - f.write("1") - mode = stat.S_IMODE(os.stat(f1).st_mode) - assert mode == 0o644 - - os.umask(0o057) - f2 = str(tmp_path / "2") - - with atomic_writing(f2) as f: - f.write("2") - - mode = stat.S_IMODE(os.stat(f2).st_mode) - assert mode == 0o620 - - -def test_atomic_writing_newlines(tmp_path): - path = str(tmp_path / "testfile") - - lf = "a\nb\nc\n" - plat = lf.replace("\n", os.linesep) - crlf = lf.replace("\n", "\r\n") - - # test default - with io.open(path, "w") as f: - f.write(lf) - with io.open(path, "r", newline="") as f: - read = f.read() - assert read == plat - - # test newline=LF - with io.open(path, "w", newline="\n") as f: - f.write(lf) - with io.open(path, "r", newline="") as f: - read = f.read() - assert read == lf - - # test newline=CRLF - with atomic_writing(str(path), newline="\r\n") as f: - f.write(lf) - with io.open(path, "r", newline="") as f: - read = f.read() - assert read == crlf - - # test newline=no convert - text = "crlf\r\ncr\rlf\n" - with atomic_writing(str(path), newline="") as f: - f.write(text) - with io.open(path, "r", newline="") as f: - read = f.read() - assert read == text diff --git a/server/jupyter_server/tests/services/contents/test_largefilemanager.py b/server/jupyter_server/tests/services/contents/test_largefilemanager.py deleted file mode 100644 index a53ae66..0000000 --- a/server/jupyter_server/tests/services/contents/test_largefilemanager.py +++ /dev/null @@ -1,109 +0,0 @@ -import pytest -import tornado - -from ...utils import expected_http_error -from jupyter_server.services.contents.largefilemanager import AsyncLargeFileManager -from jupyter_server.services.contents.largefilemanager import LargeFileManager -from jupyter_server.utils import ensure_async - - -@pytest.fixture(params=[LargeFileManager, AsyncLargeFileManager]) -def jp_large_contents_manager(request, tmp_path): - """Returns a LargeFileManager instance.""" - file_manager = request.param - return file_manager(root_dir=str(tmp_path)) - - -async def test_save(jp_large_contents_manager): - cm = jp_large_contents_manager - model = await ensure_async(cm.new_untitled(type="notebook")) - name = model["name"] - path = model["path"] - - # Get the model with 'content' - full_model = await ensure_async(cm.get(path)) - # Save the notebook - model = await ensure_async(cm.save(full_model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == name - assert model["path"] == path - - -@pytest.mark.parametrize( - "model,err_message", - [ - ( - {"name": "test", "path": "test", "chunk": 1}, - "HTTP 400: Bad Request (No file type provided)", - ), - ( - {"name": "test", "path": "test", "chunk": 1, "type": "notebook"}, - 'HTTP 400: Bad Request (File type "notebook" is not supported for large file transfer)', - ), - ( - {"name": "test", "path": "test", "chunk": 1, "type": "file"}, - "HTTP 400: Bad Request (No file content provided)", - ), - ( - { - "name": "test", - "path": "test", - "chunk": 2, - "type": "file", - "content": "test", - "format": "json", - }, - "HTTP 400: Bad Request (Must specify format of file contents as 'text' or 'base64')", - ), - ], -) -async def test_bad_save(jp_large_contents_manager, model, err_message): - with pytest.raises(tornado.web.HTTPError) as e: - await ensure_async(jp_large_contents_manager.save(model, model["path"])) - assert expected_http_error(e, 400, expected_message=err_message) - - -async def test_saving_different_chunks(jp_large_contents_manager): - cm = jp_large_contents_manager - model = { - "name": "test", - "path": "test", - "type": "file", - "content": "test==", - "format": "text", - } - name = model["name"] - path = model["path"] - await ensure_async(cm.save(model, path)) - - for chunk in (1, 2, -1): - for fm in ("text", "base64"): - full_model = await ensure_async(cm.get(path)) - full_model["chunk"] = chunk - full_model["format"] = fm - model_res = await ensure_async(cm.save(full_model, path)) - assert isinstance(model_res, dict) - assert "name" in model_res - assert "path" in model_res - assert "chunk" not in model_res - assert model_res["name"] == name - assert model_res["path"] == path - - -async def test_save_in_subdirectory(jp_large_contents_manager, tmp_path): - cm = jp_large_contents_manager - sub_dir = tmp_path / "foo" - sub_dir.mkdir() - model = await ensure_async(cm.new_untitled(path="/foo/", type="notebook")) - path = model["path"] - model = await ensure_async(cm.get(path)) - - # Change the name in the model for rename - model = await ensure_async(cm.save(model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == "Untitled.ipynb" - assert model["path"] == "foo/Untitled.ipynb" diff --git a/server/jupyter_server/tests/services/contents/test_manager.py b/server/jupyter_server/tests/services/contents/test_manager.py deleted file mode 100644 index 4da26d3..0000000 --- a/server/jupyter_server/tests/services/contents/test_manager.py +++ /dev/null @@ -1,669 +0,0 @@ -import os -import sys -import time -from itertools import combinations - -import pytest -from nbformat import v4 as nbformat -from tornado.web import HTTPError -from traitlets import TraitError - -from ...utils import expected_http_error -from jupyter_server.services.contents.filemanager import AsyncFileContentsManager -from jupyter_server.services.contents.filemanager import FileContentsManager -from jupyter_server.utils import ensure_async - - -@pytest.fixture( - params=[ - (FileContentsManager, True), - (FileContentsManager, False), - (AsyncFileContentsManager, True), - (AsyncFileContentsManager, False), - ] -) -def jp_contents_manager(request, tmp_path): - contents_manager, use_atomic_writing = request.param - return contents_manager(root_dir=str(tmp_path), use_atomic_writing=use_atomic_writing) - - -@pytest.fixture(params=[FileContentsManager, AsyncFileContentsManager]) -def jp_file_contents_manager_class(request, tmp_path): - return request.param - - -# -------------- Functions ---------------------------- - - -def _make_dir(jp_contents_manager, api_path): - """ - Make a directory. - """ - os_path = jp_contents_manager._get_os_path(api_path) - try: - os.makedirs(os_path) - except OSError: - print("Directory already exists: %r" % os_path) - - -def symlink(jp_contents_manager, src, dst): - """Make a symlink to src from dst - - src and dst are api_paths - """ - src_os_path = jp_contents_manager._get_os_path(src) - dst_os_path = jp_contents_manager._get_os_path(dst) - print(src_os_path, dst_os_path, os.path.isfile(src_os_path)) - os.symlink(src_os_path, dst_os_path) - - -def add_code_cell(notebook): - output = nbformat.new_output("display_data", {"application/javascript": "alert('hi');"}) - cell = nbformat.new_code_cell("print('hi')", outputs=[output]) - notebook.cells.append(cell) - - -async def new_notebook(jp_contents_manager): - cm = jp_contents_manager - model = await ensure_async(cm.new_untitled(type="notebook")) - name = model["name"] - path = model["path"] - - full_model = await ensure_async(cm.get(path)) - nb = full_model["content"] - nb["metadata"]["counter"] = int(1e6 * time.time()) - add_code_cell(nb) - - await ensure_async(cm.save(full_model, path)) - return nb, name, path - - -async def make_populated_dir(jp_contents_manager, api_path): - cm = jp_contents_manager - _make_dir(cm, api_path) - await ensure_async(cm.new(path="/".join([api_path, "nb.ipynb"]))) - await ensure_async(cm.new(path="/".join([api_path, "file.txt"]))) - - -async def check_populated_dir_files(jp_contents_manager, api_path): - dir_model = await ensure_async(jp_contents_manager.get(api_path)) - - assert dir_model["path"] == api_path - assert dir_model["type"] == "directory" - - for entry in dir_model["content"]: - if entry["type"] == "directory": - continue - elif entry["type"] == "file": - assert entry["name"] == "file.txt" - complete_path = "/".join([api_path, "file.txt"]) - assert entry["path"] == complete_path - elif entry["type"] == "notebook": - assert entry["name"] == "nb.ipynb" - complete_path = "/".join([api_path, "nb.ipynb"]) - assert entry["path"] == complete_path - - -# ----------------- Tests ---------------------------------- - - -def test_root_dir(jp_file_contents_manager_class, tmp_path): - fm = jp_file_contents_manager_class(root_dir=str(tmp_path)) - assert fm.root_dir == str(tmp_path) - - -def test_missing_root_dir(jp_file_contents_manager_class, tmp_path): - root = tmp_path / "notebook" / "dir" / "is" / "missing" - with pytest.raises(TraitError): - jp_file_contents_manager_class(root_dir=str(root)) - - -def test_invalid_root_dir(jp_file_contents_manager_class, tmp_path): - temp_file = tmp_path / "file.txt" - temp_file.write_text("") - with pytest.raises(TraitError): - jp_file_contents_manager_class(root_dir=str(temp_file)) - - -def test_get_os_path(jp_file_contents_manager_class, tmp_path): - fm = jp_file_contents_manager_class(root_dir=str(tmp_path)) - path = fm._get_os_path("/path/to/notebook/test.ipynb") - rel_path_list = "/path/to/notebook/test.ipynb".split("/") - fs_path = os.path.join(fm.root_dir, *rel_path_list) - assert path == fs_path - - fm = jp_file_contents_manager_class(root_dir=str(tmp_path)) - path = fm._get_os_path("test.ipynb") - fs_path = os.path.join(fm.root_dir, "test.ipynb") - assert path == fs_path - - fm = jp_file_contents_manager_class(root_dir=str(tmp_path)) - path = fm._get_os_path("////test.ipynb") - fs_path = os.path.join(fm.root_dir, "test.ipynb") - assert path == fs_path - - -def test_checkpoint_subdir(jp_file_contents_manager_class, tmp_path): - subd = "sub ∂ir" - cp_name = "test-cp.ipynb" - fm = jp_file_contents_manager_class(root_dir=str(tmp_path)) - tmp_path.joinpath(subd).mkdir() - cpm = fm.checkpoints - cp_dir = cpm.checkpoint_path("cp", "test.ipynb") - cp_subdir = cpm.checkpoint_path("cp", "/%s/test.ipynb" % subd) - assert cp_dir != cp_subdir - assert cp_dir == os.path.join(str(tmp_path), cpm.checkpoint_dir, cp_name) - - -async def test_bad_symlink(jp_file_contents_manager_class, tmp_path): - td = str(tmp_path) - - cm = jp_file_contents_manager_class(root_dir=td) - path = "test bad symlink" - _make_dir(cm, path) - - file_model = await ensure_async(cm.new_untitled(path=path, ext=".txt")) - - # create a broken symlink - symlink(cm, "target", "%s/%s" % (path, "bad symlink")) - model = await ensure_async(cm.get(path)) - - contents = {content["name"]: content for content in model["content"]} - assert "untitled.txt" in contents - assert contents["untitled.txt"] == file_model - assert "bad symlink" in contents - - -@pytest.mark.skipif(sys.platform.startswith("win"), reason="Windows doesn't detect symlink loops") -async def test_recursive_symlink(jp_file_contents_manager_class, tmp_path): - td = str(tmp_path) - - cm = jp_file_contents_manager_class(root_dir=td) - path = "test recursive symlink" - _make_dir(cm, path) - - file_model = await ensure_async(cm.new_untitled(path=path, ext=".txt")) - - # create recursive symlink - symlink(cm, "%s/%s" % (path, "recursive"), "%s/%s" % (path, "recursive")) - model = await ensure_async(cm.get(path)) - - contents = {content["name"]: content for content in model["content"]} - assert "untitled.txt" in contents - assert contents["untitled.txt"] == file_model - # recursive symlinks should not be shown in the contents manager - assert "recursive" not in contents - - -async def test_good_symlink(jp_file_contents_manager_class, tmp_path): - td = str(tmp_path) - cm = jp_file_contents_manager_class(root_dir=td) - parent = "test good symlink" - name = "good symlink" - path = "{0}/{1}".format(parent, name) - _make_dir(cm, parent) - - file_model = await ensure_async(cm.new(path=parent + "/zfoo.txt")) - - # create a good symlink - symlink(cm, file_model["path"], path) - symlink_model = await ensure_async(cm.get(path, content=False)) - dir_model = await ensure_async(cm.get(parent)) - assert sorted(dir_model["content"], key=lambda x: x["name"]) == [ - symlink_model, - file_model, - ] - - -@pytest.mark.skipif(sys.platform.startswith("win"), reason="Can't test permissions on Windows") -async def test_403(jp_file_contents_manager_class, tmp_path): - if hasattr(os, "getuid"): - if os.getuid() == 0: - raise pytest.skip("Can't test permissions as root") - - td = str(tmp_path) - cm = jp_file_contents_manager_class(root_dir=td) - model = await ensure_async(cm.new_untitled(type="file")) - os_path = cm._get_os_path(model["path"]) - - os.chmod(os_path, 0o400) - try: - with cm.open(os_path, "w") as f: - f.write("don't care") - except HTTPError as e: - assert e.status_code == 403 - - -async def test_escape_root(jp_file_contents_manager_class, tmp_path): - td = str(tmp_path) - cm = jp_file_contents_manager_class(root_dir=td) - # make foo, bar next to root - with open(os.path.join(cm.root_dir, "..", "foo"), "w") as f: - f.write("foo") - with open(os.path.join(cm.root_dir, "..", "bar"), "w") as f: - f.write("bar") - - with pytest.raises(HTTPError) as e: - await ensure_async(cm.get("..")) - expected_http_error(e, 404) - - with pytest.raises(HTTPError) as e: - await ensure_async(cm.get("foo/../../../bar")) - expected_http_error(e, 404) - - with pytest.raises(HTTPError) as e: - await ensure_async(cm.delete("../foo")) - expected_http_error(e, 404) - - with pytest.raises(HTTPError) as e: - await ensure_async(cm.rename("../foo", "../bar")) - expected_http_error(e, 404) - - with pytest.raises(HTTPError) as e: - await ensure_async( - cm.save( - model={ - "type": "file", - "content": "", - "format": "text", - }, - path="../foo", - ) - ) - expected_http_error(e, 404) - - -async def test_new_untitled(jp_contents_manager): - cm = jp_contents_manager - # Test in root directory - model = await ensure_async(cm.new_untitled(type="notebook")) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert "type" in model - assert model["type"] == "notebook" - assert model["name"] == "Untitled.ipynb" - assert model["path"] == "Untitled.ipynb" - - # Test in sub-directory - model = await ensure_async(cm.new_untitled(type="directory")) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert "type" in model - assert model["type"] == "directory" - assert model["name"] == "Untitled Folder" - assert model["path"] == "Untitled Folder" - sub_dir = model["path"] - - model = await ensure_async(cm.new_untitled(path=sub_dir)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert "type" in model - assert model["type"] == "file" - assert model["name"] == "untitled" - assert model["path"] == "%s/untitled" % sub_dir - - # Test with a compound extension - model = await ensure_async(cm.new_untitled(path=sub_dir, ext=".foo.bar")) - assert model["name"] == "untitled.foo.bar" - model = await ensure_async(cm.new_untitled(path=sub_dir, ext=".foo.bar")) - assert model["name"] == "untitled1.foo.bar" - - -async def test_modified_date(jp_contents_manager): - cm = jp_contents_manager - # Create a new notebook. - nb, name, path = await new_notebook(cm) - model = await ensure_async(cm.get(path)) - - # Add a cell and save. - add_code_cell(model["content"]) - await ensure_async(cm.save(model, path)) - - # Reload notebook and verify that last_modified incremented. - saved = await ensure_async(cm.get(path)) - assert saved["last_modified"] >= model["last_modified"] - - # Move the notebook and verify that last_modified stayed the same. - # (The frontend fires a warning if last_modified increases on the - # renamed file.) - new_path = "renamed.ipynb" - await ensure_async(cm.rename(path, new_path)) - renamed = await ensure_async(cm.get(new_path)) - assert renamed["last_modified"] >= saved["last_modified"] - - -async def test_get(jp_contents_manager): - cm = jp_contents_manager - # Create a notebook - model = await ensure_async(cm.new_untitled(type="notebook")) - name = model["name"] - path = model["path"] - - # Check that we 'get' on the notebook we just created - model2 = await ensure_async(cm.get(path)) - assert isinstance(model2, dict) - assert "name" in model2 - assert "path" in model2 - assert model["name"] == name - assert model["path"] == path - - nb_as_file = await ensure_async(cm.get(path, content=True, type="file")) - assert nb_as_file["path"] == path - assert nb_as_file["type"] == "file" - assert nb_as_file["format"] == "text" - assert not isinstance(nb_as_file["content"], dict) - - nb_as_bin_file = await ensure_async(cm.get(path, content=True, type="file", format="base64")) - assert nb_as_bin_file["format"] == "base64" - - # Test in sub-directory - sub_dir = "/foo/" - _make_dir(cm, "foo") - await ensure_async(cm.new_untitled(path=sub_dir, ext=".ipynb")) - model2 = await ensure_async(cm.get(sub_dir + name)) - assert isinstance(model2, dict) - assert "name" in model2 - assert "path" in model2 - assert "content" in model2 - assert model2["name"] == "Untitled.ipynb" - assert model2["path"] == "{0}/{1}".format(sub_dir.strip("/"), name) - - # Test with a regular file. - file_model_path = (await ensure_async(cm.new_untitled(path=sub_dir, ext=".txt")))["path"] - file_model = await ensure_async(cm.get(file_model_path)) - expected_model = { - "content": "", - "format": "text", - "mimetype": "text/plain", - "name": "untitled.txt", - "path": "foo/untitled.txt", - "type": "file", - "writable": True, - } - # Assert expected model is in file_model - for key, value in expected_model.items(): - assert file_model[key] == value - assert "created" in file_model - assert "last_modified" in file_model - - # Create a sub-sub directory to test getting directory contents with a - # subdir. - _make_dir(cm, "foo/bar") - dirmodel = await ensure_async(cm.get("foo")) - assert dirmodel["type"] == "directory" - assert isinstance(dirmodel["content"], list) - assert len(dirmodel["content"]) == 3 - assert dirmodel["path"] == "foo" - assert dirmodel["name"] == "foo" - - # Directory contents should match the contents of each individual entry - # when requested with content=False. - model2_no_content = await ensure_async(cm.get(sub_dir + name, content=False)) - file_model_no_content = await ensure_async(cm.get("foo/untitled.txt", content=False)) - sub_sub_dir_no_content = await ensure_async(cm.get("foo/bar", content=False)) - assert sub_sub_dir_no_content["path"] == "foo/bar" - assert sub_sub_dir_no_content["name"] == "bar" - - for entry in dirmodel["content"]: - # Order isn't guaranteed by the spec, so this is a hacky way of - # verifying that all entries are matched. - if entry["path"] == sub_sub_dir_no_content["path"]: - assert entry == sub_sub_dir_no_content - elif entry["path"] == model2_no_content["path"]: - assert entry == model2_no_content - elif entry["path"] == file_model_no_content["path"]: - assert entry == file_model_no_content - else: - assert False, "Unexpected directory entry: %s" % entry() - - with pytest.raises(HTTPError): - await ensure_async(cm.get("foo", type="file")) - - -async def test_update(jp_contents_manager): - cm = jp_contents_manager - # Create a notebook. - model = await ensure_async(cm.new_untitled(type="notebook")) - name = model["name"] - path = model["path"] - - # Change the name in the model for rename - model["path"] = "test.ipynb" - model = await ensure_async(cm.update(model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == "test.ipynb" - - # Make sure the old name is gone - with pytest.raises(HTTPError): - await ensure_async(cm.get(path)) - - # Test in sub-directory - # Create a directory and notebook in that directory - sub_dir = "/foo/" - _make_dir(cm, "foo") - model = await ensure_async(cm.new_untitled(path=sub_dir, type="notebook")) - path = model["path"] - - # Change the name in the model for rename - d = path.rsplit("/", 1)[0] - new_path = model["path"] = d + "/test_in_sub.ipynb" - model = await ensure_async(cm.update(model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == "test_in_sub.ipynb" - assert model["path"] == new_path - - # Make sure the old name is gone - with pytest.raises(HTTPError): - await ensure_async(cm.get(path)) - - -async def test_save(jp_contents_manager): - cm = jp_contents_manager - # Create a notebook - model = await ensure_async(cm.new_untitled(type="notebook")) - name = model["name"] - path = model["path"] - - # Get the model with 'content' - full_model = await ensure_async(cm.get(path)) - - # Save the notebook - model = await ensure_async(cm.save(full_model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == name - assert model["path"] == path - - # Test in sub-directory - # Create a directory and notebook in that directory - sub_dir = "/foo/" - _make_dir(cm, "foo") - model = await ensure_async(cm.new_untitled(path=sub_dir, type="notebook")) - path = model["path"] - model = await ensure_async(cm.get(path)) - - # Change the name in the model for rename - model = await ensure_async(cm.save(model, path)) - assert isinstance(model, dict) - assert "name" in model - assert "path" in model - assert model["name"] == "Untitled.ipynb" - assert model["path"] == "foo/Untitled.ipynb" - - -async def test_delete(jp_contents_manager): - cm = jp_contents_manager - # Create a notebook - nb, name, path = await new_notebook(cm) - - # Delete the notebook - await ensure_async(cm.delete(path)) - - # Check that deleting a non-existent path raises an error. - with pytest.raises(HTTPError): - await ensure_async(cm.delete(path)) - - # Check that a 'get' on the deleted notebook raises and error - with pytest.raises(HTTPError): - await ensure_async(cm.get(path)) - - -@pytest.mark.parametrize( - "delete_to_trash, always_delete, error", - ( - [True, True, False], - # on linux test folder may not be on home folder drive - # => if this is the case, _check_trash will be False - [True, False, None], - [False, True, False], - [False, False, True], - ), -) -async def test_delete_non_empty_folder(delete_to_trash, always_delete, error, jp_contents_manager): - cm = jp_contents_manager - cm.delete_to_trash = delete_to_trash - cm.always_delete_dir = always_delete - - dir = "to_delete" - - await make_populated_dir(cm, dir) - await check_populated_dir_files(cm, dir) - - if error is None: - error = False - if sys.platform == "win32": - error = True - elif sys.platform == "linux": - file_dev = os.stat(cm.root_dir).st_dev - home_dev = os.stat(os.path.expanduser("~")).st_dev - error = file_dev != home_dev - - if error: - with pytest.raises( - HTTPError, - match=r"HTTP 400: Bad Request \(Directory .*?to_delete not empty\)", - ): - await ensure_async(cm.delete_file(dir)) - else: - await ensure_async(cm.delete_file(dir)) - assert await ensure_async(cm.dir_exists(dir)) == False - - -async def test_rename(jp_contents_manager): - cm = jp_contents_manager - # Create a new notebook - nb, name, path = await new_notebook(cm) - - # Rename the notebook - await ensure_async(cm.rename(path, "changed_path")) - - # Attempting to get the notebook under the old name raises an error - with pytest.raises(HTTPError): - await ensure_async(cm.get(path)) - # Fetching the notebook under the new name is successful - assert isinstance(await ensure_async(cm.get("changed_path")), dict) - - # Ported tests on nested directory renaming from pgcontents - all_dirs = ["foo", "bar", "foo/bar", "foo/bar/foo", "foo/bar/foo/bar"] - unchanged_dirs = all_dirs[:2] - changed_dirs = all_dirs[2:] - - for _dir in all_dirs: - await make_populated_dir(cm, _dir) - await check_populated_dir_files(cm, _dir) - - # Renaming to an existing directory should fail - for src, dest in combinations(all_dirs, 2): - with pytest.raises(HTTPError) as e: - await ensure_async(cm.rename(src, dest)) - assert expected_http_error(e, 409) - - # Creating a notebook in a non_existant directory should fail - with pytest.raises(HTTPError) as e: - await ensure_async(cm.new_untitled("foo/bar_diff", ext=".ipynb")) - assert expected_http_error(e, 404) - - await ensure_async(cm.rename("foo/bar", "foo/bar_diff")) - - # Assert that unchanged directories remain so - for unchanged in unchanged_dirs: - await check_populated_dir_files(cm, unchanged) - - # Assert changed directories can no longer be accessed under old names - for changed_dirname in changed_dirs: - with pytest.raises(HTTPError) as e: - await ensure_async(cm.get(changed_dirname)) - assert expected_http_error(e, 404) - new_dirname = changed_dirname.replace("foo/bar", "foo/bar_diff", 1) - await check_populated_dir_files(cm, new_dirname) - - # Created a notebook in the renamed directory should work - await ensure_async(cm.new_untitled("foo/bar_diff", ext=".ipynb")) - - -async def test_delete_root(jp_contents_manager): - cm = jp_contents_manager - with pytest.raises(HTTPError) as e: - await ensure_async(cm.delete("")) - assert expected_http_error(e, 400) - - -async def test_copy(jp_contents_manager): - cm = jp_contents_manager - parent = "ÃĨ b" - name = "nb √.ipynb" - path = "{0}/{1}".format(parent, name) - _make_dir(cm, parent) - - orig = await ensure_async(cm.new(path=path)) - # copy with unspecified name - copy = await ensure_async(cm.copy(path)) - assert copy["name"] == orig["name"].replace(".ipynb", "-Copy1.ipynb") - - # copy with specified name - copy2 = await ensure_async(cm.copy(path, "ÃĨ b/copy 2.ipynb")) - assert copy2["name"] == "copy 2.ipynb" - assert copy2["path"] == "ÃĨ b/copy 2.ipynb" - # copy with specified path - copy2 = await ensure_async(cm.copy(path, "/")) - assert copy2["name"] == name - assert copy2["path"] == name - - -async def test_mark_trusted_cells(jp_contents_manager): - cm = jp_contents_manager - nb, name, path = await new_notebook(cm) - - cm.mark_trusted_cells(nb, path) - for cell in nb.cells: - if cell.cell_type == "code": - assert not cell.metadata.trusted - - await ensure_async(cm.trust_notebook(path)) - nb = (await ensure_async(cm.get(path)))["content"] - for cell in nb.cells: - if cell.cell_type == "code": - assert cell.metadata.trusted - - -async def test_check_and_sign(jp_contents_manager): - cm = jp_contents_manager - nb, name, path = await new_notebook(cm) - - cm.mark_trusted_cells(nb, path) - cm.check_and_sign(nb, path) - assert not cm.notary.check_signature(nb) - - await ensure_async(cm.trust_notebook(path)) - nb = (await ensure_async(cm.get(path)))["content"] - cm.mark_trusted_cells(nb, path) - cm.check_and_sign(nb, path) - assert cm.notary.check_signature(nb) diff --git a/server/jupyter_server/tests/services/kernels/__init__.py b/server/jupyter_server/tests/services/kernels/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/kernels/test_api.py b/server/jupyter_server/tests/services/kernels/test_api.py deleted file mode 100644 index 50be5fb..0000000 --- a/server/jupyter_server/tests/services/kernels/test_api.py +++ /dev/null @@ -1,277 +0,0 @@ -import json -import os -import time - -import jupyter_client -import pytest -import tornado -from jupyter_client.kernelspec import NATIVE_KERNEL_NAME -from tornado.httpclient import HTTPClientError - -from ...utils import expected_http_error -from jupyter_server.utils import url_path_join - - -TEST_TIMEOUT = 20 - - -@pytest.fixture -def pending_kernel_is_ready(jp_serverapp): - async def _(kernel_id): - km = jp_serverapp.kernel_manager - if getattr(km, "use_pending_kernels", False): - kernel = km.get_kernel(kernel_id) - if getattr(kernel, "ready"): - await kernel.ready - - return _ - - -configs = [ - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.MappingKernelManager" - } - }, - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager" - } - }, -] - - -# Pending kernels was released in Jupyter Client 7.1 -# It is currently broken on Windows (Jan 2022). When fixed, we can remove the Windows check. -# See https://github.com/jupyter-server/jupyter_server/issues/672 -if os.name != "nt" and jupyter_client._version.version_info >= (7, 1): - # Add a pending kernels condition - c = { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager" - }, - "AsyncMappingKernelManager": {"use_pending_kernels": True}, - } - configs.append(c) - - -@pytest.fixture(params=configs) -def jp_server_config(request): - return request.param - - -async def test_no_kernels(jp_fetch): - r = await jp_fetch("https://github.com/api", "kernels", method="GET") - kernels = json.loads(r.body.decode()) - assert kernels == [] - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_default_kernels(jp_fetch, jp_base_url, jp_cleanup_subprocesses): - r = await jp_fetch("https://github.com/api", "kernels", method="POST", allow_nonstandard_methods=True) - kernel = json.loads(r.body.decode()) - assert r.headers["location"] == url_path_join(jp_base_url, "/api/kernels/", kernel["id"]) - assert r.code == 201 - assert isinstance(kernel, dict) - - report_uri = url_path_join(jp_base_url, "/api/security/csp-report") - expected_csp = "; ".join( - ["frame-ancestors 'self'", "report-uri " + report_uri, "default-src 'none'"] - ) - assert r.headers["Content-Security-Policy"] == expected_csp - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_main_kernel_handler( - jp_fetch, jp_base_url, jp_cleanup_subprocesses, jp_serverapp, pending_kernel_is_ready -): - # Start the first kernel - r = await jp_fetch( - "api", "kernels", method="POST", body=json.dumps({"name": NATIVE_KERNEL_NAME}) - ) - kernel1 = json.loads(r.body.decode()) - assert r.headers["location"] == url_path_join(jp_base_url, "/api/kernels/", kernel1["id"]) - assert r.code == 201 - assert isinstance(kernel1, dict) - - report_uri = url_path_join(jp_base_url, "/api/security/csp-report") - expected_csp = "; ".join( - ["frame-ancestors 'self'", "report-uri " + report_uri, "default-src 'none'"] - ) - assert r.headers["Content-Security-Policy"] == expected_csp - - # Check that the kernel is found in the kernel list - r = await jp_fetch("https://github.com/api", "kernels", method="GET") - kernel_list = json.loads(r.body.decode()) - assert r.code == 200 - assert isinstance(kernel_list, list) - assert kernel_list[0]["id"] == kernel1["id"] - assert kernel_list[0]["name"] == kernel1["name"] - - # Start a second kernel - r = await jp_fetch( - "api", "kernels", method="POST", body=json.dumps({"name": NATIVE_KERNEL_NAME}) - ) - kernel2 = json.loads(r.body.decode()) - assert isinstance(kernel2, dict) - - # Get kernel list again - r = await jp_fetch("https://github.com/api", "kernels", method="GET") - kernel_list = json.loads(r.body.decode()) - assert r.code == 200 - assert isinstance(kernel_list, list) - assert len(kernel_list) == 2 - - # Interrupt a kernel - await pending_kernel_is_ready(kernel2["id"]) - r = await jp_fetch( - "api", - "kernels", - kernel2["id"], - "interrupt", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 204 - - # Restart a kernel - await pending_kernel_is_ready(kernel2["id"]) - r = await jp_fetch( - "api", - "kernels", - kernel2["id"], - "restart", - method="POST", - allow_nonstandard_methods=True, - ) - restarted_kernel = json.loads(r.body.decode()) - assert restarted_kernel["id"] == kernel2["id"] - assert restarted_kernel["name"] == kernel2["name"] - - # Start a kernel with a path - r = await jp_fetch( - "api", - "kernels", - method="POST", - body=json.dumps({"name": NATIVE_KERNEL_NAME, "path": "/foo"}), - ) - kernel3 = json.loads(r.body.decode()) - assert isinstance(kernel3, dict) - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_kernel_handler(jp_fetch, jp_cleanup_subprocesses, pending_kernel_is_ready): - # Create a kernel - r = await jp_fetch( - "api", "kernels", method="POST", body=json.dumps({"name": NATIVE_KERNEL_NAME}) - ) - kernel_id = json.loads(r.body.decode())["id"] - r = await jp_fetch("https://github.com/api", "kernels", kernel_id, method="GET") - kernel = json.loads(r.body.decode()) - assert r.code == 200 - assert isinstance(kernel, dict) - assert "id" in kernel - assert kernel["id"] == kernel_id - - # Requests a bad kernel id. - bad_id = "111-111-111-111-111" - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/api", "kernels", bad_id, method="GET") - assert expected_http_error(e, 404) - - # Delete kernel with id. - await pending_kernel_is_ready(kernel_id) - r = await jp_fetch( - "api", - "kernels", - kernel_id, - method="DELETE", - ) - assert r.code == 204 - - # Get list of kernels - try: - await pending_kernel_is_ready(kernel_id) - # If the kernel is already deleted, no need to await. - except tornado.web.HTTPError: - pass - r = await jp_fetch("https://github.com/api", "kernels", method="GET") - kernel_list = json.loads(r.body.decode()) - assert kernel_list == [] - - # Request to delete a non-existent kernel id - bad_id = "111-111-111-111-111" - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/api", "kernels", bad_id, method="DELETE") - assert expected_http_error(e, 404, "Kernel does not exist: " + bad_id) - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_kernel_handler_startup_error( - jp_fetch, jp_cleanup_subprocesses, jp_serverapp, jp_kernelspecs -): - if getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - return - - # Create a kernel - with pytest.raises(HTTPClientError): - await jp_fetch("https://github.com/api", "kernels", method="POST", body=json.dumps({"name": "bad"})) - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_kernel_handler_startup_error_pending( - jp_fetch, jp_ws_fetch, jp_cleanup_subprocesses, jp_serverapp, jp_kernelspecs -): - if not getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - return - - jp_serverapp.kernel_manager.use_pending_kernels = True - # Create a kernel - r = await jp_fetch("https://github.com/api", "kernels", method="POST", body=json.dumps({"name": "bad"})) - kid = json.loads(r.body.decode())["id"] - - with pytest.raises(HTTPClientError): - await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_connection( - jp_fetch, jp_ws_fetch, jp_http_port, jp_auth_header, jp_cleanup_subprocesses -): - # Create kernel - r = await jp_fetch( - "api", "kernels", method="POST", body=json.dumps({"name": NATIVE_KERNEL_NAME}) - ) - kid = json.loads(r.body.decode())["id"] - - # Get kernel info - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 0 - - # Open a websocket connection. - ws = await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - # Test that it was opened. - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 1 - - # Close websocket - ws.close() - # give it some time to close on the other side: - for i in range(10): - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - if model["connections"] > 0: - time.sleep(0.1) - else: - break - - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 0 - await jp_cleanup_subprocesses() diff --git a/server/jupyter_server/tests/services/kernels/test_config.py b/server/jupyter_server/tests/services/kernels/test_config.py deleted file mode 100644 index 9b58a8c..0000000 --- a/server/jupyter_server/tests/services/kernels/test_config.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from traitlets.config import Config - -from jupyter_server.services.kernels.kernelmanager import AsyncMappingKernelManager - - -@pytest.fixture -def jp_server_config(): - return Config( - {"ServerApp": {"MappingKernelManager": {"allowed_message_types": ["kernel_info_request"]}}} - ) - - -def test_config(jp_serverapp): - assert jp_serverapp.kernel_manager.allowed_message_types == ["kernel_info_request"] - - -async def test_async_kernel_manager(jp_configurable_serverapp): - argv = [ - "--ServerApp.kernel_manager_class=jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager" - ] - app = jp_configurable_serverapp(argv=argv) - assert isinstance(app.kernel_manager, AsyncMappingKernelManager) diff --git a/server/jupyter_server/tests/services/kernels/test_cull.py b/server/jupyter_server/tests/services/kernels/test_cull.py deleted file mode 100644 index e2b5f0f..0000000 --- a/server/jupyter_server/tests/services/kernels/test_cull.py +++ /dev/null @@ -1,127 +0,0 @@ -import asyncio -import json -import os -import platform - -import jupyter_client -import pytest -from tornado.httpclient import HTTPClientError -from traitlets.config import Config - - -CULL_TIMEOUT = 30 if platform.python_implementation() == "PyPy" else 5 -CULL_INTERVAL = 1 - - -@pytest.mark.parametrize( - "jp_server_config", - [ - # Test the synchronous case - Config( - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.MappingKernelManager", - "MappingKernelManager": { - "cull_idle_timeout": CULL_TIMEOUT, - "cull_interval": CULL_INTERVAL, - "cull_connected": False, - }, - } - } - ), - # Test the async case - Config( - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager", - "AsyncMappingKernelManager": { - "cull_idle_timeout": CULL_TIMEOUT, - "cull_interval": CULL_INTERVAL, - "cull_connected": False, - }, - } - } - ), - ], -) -async def test_cull_idle(jp_fetch, jp_ws_fetch, jp_cleanup_subprocesses): - r = await jp_fetch("https://github.com/api", "kernels", method="POST", allow_nonstandard_methods=True) - kernel = json.loads(r.body.decode()) - kid = kernel["id"] - - # Open a websocket connection. - ws = await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 1 - culled = await get_cull_status(kid, jp_fetch) # connected, should not be culled - assert not culled - ws.close() - culled = await get_cull_status(kid, jp_fetch) # not connected, should be culled - assert culled - await jp_cleanup_subprocesses() - - -# Pending kernels was released in Jupyter Client 7.1 -# It is currently broken on Windows (Jan 2022). When fixed, we can remove the Windows check. -# See https://github.com/jupyter-server/jupyter_server/issues/672 -@pytest.mark.skipif( - os.name == "nt" or jupyter_client._version.version_info < (7, 1), - reason="Pending kernels require jupyter_client >= 7.1 on non-Windows", -) -@pytest.mark.parametrize( - "jp_server_config", - [ - Config( - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager", - "AsyncMappingKernelManager": { - "cull_idle_timeout": CULL_TIMEOUT, - "cull_interval": CULL_INTERVAL, - "cull_connected": False, - "default_kernel_name": "bad", - "use_pending_kernels": True, - }, - } - } - ) - ], -) -@pytest.mark.timeout(30) -async def test_cull_dead( - jp_fetch, jp_ws_fetch, jp_serverapp, jp_cleanup_subprocesses, jp_kernelspecs -): - r = await jp_fetch("https://github.com/api", "kernels", method="POST", allow_nonstandard_methods=True) - kernel = json.loads(r.body.decode()) - kid = kernel["id"] - - # Open a websocket connection. - with pytest.raises(HTTPClientError): - await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 0 - culled = await get_cull_status(kid, jp_fetch) # connected, should not be culled - assert culled - await jp_cleanup_subprocesses() - - -async def get_cull_status(kid, jp_fetch): - frequency = 0.5 - culled = False - for _ in range( - int((CULL_TIMEOUT + CULL_INTERVAL) / frequency) - ): # Timeout + Interval will ensure cull - try: - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - json.loads(r.body.decode()) - except HTTPClientError as e: - assert e.code == 404 - culled = True - break - else: - await asyncio.sleep(frequency) - return culled diff --git a/server/jupyter_server/tests/services/kernelspecs/__init__.py b/server/jupyter_server/tests/services/kernelspecs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/kernelspecs/test_api.py b/server/jupyter_server/tests/services/kernelspecs/test_api.py deleted file mode 100644 index 9471420..0000000 --- a/server/jupyter_server/tests/services/kernelspecs/test_api.py +++ /dev/null @@ -1,79 +0,0 @@ -import json - -import pytest -import tornado -from jupyter_client.kernelspec import NATIVE_KERNEL_NAME - -from ...utils import expected_http_error -from ...utils import some_resource - - -async def test_list_kernelspecs_bad(jp_fetch, jp_kernelspecs, jp_data_dir): - bad_kernel_dir = jp_data_dir.joinpath(jp_data_dir, "kernels", "bad2") - bad_kernel_dir.mkdir(parents=True) - bad_kernel_json = bad_kernel_dir.joinpath("kernel.json") - bad_kernel_json.write_text("garbage") - - r = await jp_fetch("https://github.com/api", "kernelspecs", method="GET") - model = json.loads(r.body.decode()) - assert isinstance(model, dict) - assert model["default"] == NATIVE_KERNEL_NAME - specs = model["kernelspecs"] - assert isinstance(specs, dict) - assert len(specs) > 2 - - -async def test_list_kernelspecs(jp_fetch, jp_kernelspecs): - r = await jp_fetch("https://github.com/api", "kernelspecs", method="GET") - model = json.loads(r.body.decode()) - assert isinstance(model, dict) - assert model["default"] == NATIVE_KERNEL_NAME - specs = model["kernelspecs"] - assert isinstance(specs, dict) - assert len(specs) > 2 - - def is_sample_kernelspec(s): - return s["name"] == "sample" and s["spec"]["display_name"] == "Test kernel" - - def is_default_kernelspec(s): - return s["name"] == NATIVE_KERNEL_NAME and s["spec"]["display_name"].startswith("Python") - - assert any(is_sample_kernelspec(s) for s in specs.values()), specs - assert any(is_default_kernelspec(s) for s in specs.values()), specs - - -async def test_get_kernelspecs(jp_fetch, jp_kernelspecs): - r = await jp_fetch("https://github.com/api", "kernelspecs", "Sample", method="GET") - model = json.loads(r.body.decode()) - assert model["name"].lower() == "sample" - assert isinstance(model["spec"], dict) - assert model["spec"]["display_name"] == "Test kernel" - assert isinstance(model["resources"], dict) - - -async def test_get_kernelspec_spaces(jp_fetch, jp_kernelspecs): - r = await jp_fetch("https://github.com/api", "kernelspecs", "sample%202", method="GET") - model = json.loads(r.body.decode()) - assert model["name"].lower() == "sample 2" - - -async def test_get_nonexistant_kernelspec(jp_fetch, jp_kernelspecs): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/api", "kernelspecs", "nonexistant", method="GET") - assert expected_http_error(e, 404) - - -async def test_get_kernel_resource_file(jp_fetch, jp_kernelspecs): - r = await jp_fetch("https://github.com/kernelspecs", "sAmple", "resource.txt", method="GET") - res = r.body.decode("utf-8") - assert res == some_resource - - -async def test_get_nonexistant_resource(jp_fetch, jp_kernelspecs): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/kernelspecs", "nonexistant", "resource.txt", method="GET") - assert expected_http_error(e, 404) - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/kernelspecs", "sample", "nonexistant.txt", method="GET") - assert expected_http_error(e, 404) diff --git a/server/jupyter_server/tests/services/nbconvert/__init__.py b/server/jupyter_server/tests/services/nbconvert/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/nbconvert/test_api.py b/server/jupyter_server/tests/services/nbconvert/test_api.py deleted file mode 100644 index ae028dd..0000000 --- a/server/jupyter_server/tests/services/nbconvert/test_api.py +++ /dev/null @@ -1,14 +0,0 @@ -import json - - -async def test_list_formats(jp_fetch): - r = await jp_fetch("https://github.com/api", "nbconvert", method="GET") - formats = json.loads(r.body.decode()) - # Verify the type of the response. - assert isinstance(formats, dict) - # Verify that all returned formats have an - # output mimetype defined. - required_keys_present = [] - for name, data in formats.items(): - required_keys_present.append("output_mimetype" in data) - assert all(required_keys_present), "All returned formats must have a `output_mimetype` key." diff --git a/server/jupyter_server/tests/services/sessions/__init__.py b/server/jupyter_server/tests/services/sessions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/services/sessions/test_api.py b/server/jupyter_server/tests/services/sessions/test_api.py deleted file mode 100644 index 3bbc5d0..0000000 --- a/server/jupyter_server/tests/services/sessions/test_api.py +++ /dev/null @@ -1,600 +0,0 @@ -import json -import os -import shutil -import time - -import jupyter_client -import pytest -import tornado -from jupyter_client.ioloop import AsyncIOLoopKernelManager -from nbformat import writes -from nbformat.v4 import new_notebook -from tornado.httpclient import HTTPClientError -from traitlets import default - -from ...utils import expected_http_error -from jupyter_server.services.kernels.kernelmanager import AsyncMappingKernelManager -from jupyter_server.utils import url_path_join - - -TEST_TIMEOUT = 20 - - -j = lambda r: json.loads(r.body.decode()) - - -class NewPortsKernelManager(AsyncIOLoopKernelManager): - @default("cache_ports") - def _default_cache_ports(self) -> bool: - return False - - async def restart_kernel(self, now: bool = False, newports: bool = True, **kw) -> None: - self.log.debug(f"DEBUG**** calling super().restart_kernel with newports={newports}") - return await super().restart_kernel(now=now, newports=newports, **kw) - - -class NewPortsMappingKernelManager(AsyncMappingKernelManager): - @default("kernel_manager_class") - def _default_kernel_manager_class(self): - self.log.debug("NewPortsMappingKernelManager in _default_kernel_manager_class!") - return "jupyter_server.tests.services.sessions.test_api.NewPortsKernelManager" - - -configs = [ - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.MappingKernelManager" - } - }, - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.services.kernels.kernelmanager.AsyncMappingKernelManager" - } - }, - { - "ServerApp": { - "kernel_manager_class": "jupyter_server.tests.services.sessions.test_api.NewPortsMappingKernelManager" - } - }, -] - - -# Pending kernels was released in Jupyter Client 7.1 -# It is currently broken on Windows (Jan 2022). When fixed, we can remove the Windows check. -# See https://github.com/jupyter-server/jupyter_server/issues/672 -if os.name != "nt" and jupyter_client._version.version_info >= (7, 1): - # Add a pending kernels condition - c = { - "ServerApp": { - "kernel_manager_class": "jupyter_server.tests.services.sessions.test_api.NewPortsMappingKernelManager" - }, - "AsyncMappingKernelManager": {"use_pending_kernels": True}, - } - configs.append(c) - - -@pytest.fixture(params=configs) -def jp_server_config(request): - return request.param - - -class SessionClient: - def __init__(self, fetch_callable): - self.jp_fetch = fetch_callable - - async def _req(self, *args, method, body=None): - if body is not None: - body = json.dumps(body) - - r = await self.jp_fetch( - "api", - "sessions", - *args, - method=method, - body=body, - allow_nonstandard_methods=True, - ) - return r - - async def list(self): - return await self._req(method="GET") - - async def get(self, id): - return await self._req(id, method="GET") - - async def create(self, path, type="notebook", kernel_name=None, kernel_id=None): - body = { - "path": path, - "type": type, - "kernel": {"name": kernel_name, "id": kernel_id}, - } - return await self._req(method="POST", body=body) - - def create_deprecated(self, path): - body = {"notebook": {"path": path}, "kernel": {"name": "python", "id": "foo"}} - return self._req(method="POST", body=body) - - def modify_path(self, id, path): - body = {"path": path} - return self._req(id, method="PATCH", body=body) - - def modify_path_deprecated(self, id, path): - body = {"notebook": {"path": path}} - return self._req(id, method="PATCH", body=body) - - def modify_type(self, id, type): - body = {"type": type} - return self._req(id, method="PATCH", body=body) - - def modify_kernel_name(self, id, kernel_name): - body = {"kernel": {"name": kernel_name}} - return self._req(id, method="PATCH", body=body) - - def modify_kernel_id(self, id, kernel_id): - # Also send a dummy name to show that id takes precedence. - body = {"kernel": {"id": kernel_id, "name": "foo"}} - return self._req(id, method="PATCH", body=body) - - async def delete(self, id): - return await self._req(id, method="DELETE") - - async def cleanup(self): - resp = await self.list() - sessions = j(resp) - for session in sessions: - await self.delete(session["id"]) - time.sleep(0.1) - - -@pytest.fixture -def session_is_ready(jp_serverapp): - """Wait for the kernel started by a session to be ready. - - This is useful when working with pending kernels. - """ - - async def _(session_id): - mkm = jp_serverapp.kernel_manager - if getattr(mkm, "use_pending_kernels", False): - sm = jp_serverapp.session_manager - session = await sm.get_session(session_id=session_id) - kernel_id = session["kernel"]["id"] - kernel = mkm.get_kernel(kernel_id) - if getattr(kernel, "ready"): - await kernel.ready - - return _ - - -@pytest.fixture -def session_client(jp_root_dir, jp_fetch): - subdir = jp_root_dir.joinpath("foo") - subdir.mkdir() - - # Write a notebook to subdir. - nb = new_notebook() - nb_str = writes(nb, version=4) - nbpath = subdir.joinpath("nb1.ipynb") - nbpath.write_text(nb_str, encoding="utf-8") - - # Yield a session client - client = SessionClient(jp_fetch) - yield client - - # Remove subdir - shutil.rmtree(str(subdir), ignore_errors=True) - - -def assert_kernel_equality(actual, expected): - """Compares kernel models after taking into account that execution_states - may differ from 'starting' to 'idle'. The 'actual' argument is the - current state (which may have an 'idle' status) while the 'expected' - argument is the previous state (which may have a 'starting' status). - """ - actual.pop("execution_state", None) - actual.pop("last_activity", None) - expected.pop("execution_state", None) - expected.pop("last_activity", None) - assert actual == expected - - -def assert_session_equality(actual, expected): - """Compares session models. `actual` is the most current session, - while `expected` is the target of the comparison. This order - matters when comparing the kernel sub-models. - """ - assert actual["id"] == expected["id"] - assert actual["path"] == expected["path"] - assert actual["type"] == expected["type"] - assert_kernel_equality(actual["kernel"], expected["kernel"]) - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create(session_client, jp_base_url, jp_cleanup_subprocesses, jp_serverapp): - # Make sure no sessions exist. - resp = await session_client.list() - sessions = j(resp) - assert len(sessions) == 0 - - # Create a session. - resp = await session_client.create("foo/nb1.ipynb") - assert resp.code == 201 - new_session = j(resp) - assert "id" in new_session - assert new_session["path"] == "foo/nb1.ipynb" - assert new_session["type"] == "notebook" - assert resp.headers["Location"] == url_path_join( - jp_base_url, "/api/sessions/", new_session["id"] - ) - - # Make sure kernel is in expected state - kid = new_session["kernel"]["id"] - kernel = jp_serverapp.kernel_manager.get_kernel(kid) - - if hasattr(kernel, "ready") and os.name != "nt": - km = jp_serverapp.kernel_manager - if isinstance(km, AsyncMappingKernelManager): - assert kernel.ready.done() == (not km.use_pending_kernels) - else: - assert kernel.ready.done() - - # Check that the new session appears in list. - resp = await session_client.list() - sessions = j(resp) - assert len(sessions) == 1 - assert_session_equality(sessions[0], new_session) - - # Retrieve that session. - sid = new_session["id"] - resp = await session_client.get(sid) - got = j(resp) - assert_session_equality(got, new_session) - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_bad( - session_client, jp_base_url, jp_cleanup_subprocesses, jp_serverapp, jp_kernelspecs -): - if getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - return - - # Make sure no sessions exist. - jp_serverapp.kernel_manager.default_kernel_name = "bad" - resp = await session_client.list() - sessions = j(resp) - assert len(sessions) == 0 - - # Create a session. - with pytest.raises(HTTPClientError): - await session_client.create("foo/nb1.ipynb") - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_bad_pending( - session_client, - jp_base_url, - jp_ws_fetch, - jp_cleanup_subprocesses, - jp_serverapp, - jp_kernelspecs, -): - if not getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - return - - # Make sure no sessions exist. - jp_serverapp.kernel_manager.default_kernel_name = "bad" - resp = await session_client.list() - sessions = j(resp) - assert len(sessions) == 0 - - # Create a session. - resp = await session_client.create("foo/nb1.ipynb") - assert resp.code == 201 - - # Open a websocket connection. - kid = j(resp)["kernel"]["id"] - with pytest.raises(HTTPClientError): - await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - # Get the updated kernel state - resp = await session_client.list() - session = j(resp)[0] - assert session["kernel"]["execution_state"] == "dead" - if os.name != "nt": - assert "non_existent_path" in session["kernel"]["reason"] - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_file_session( - session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/nb1.py", type="file") - assert resp.code == 201 - newsession = j(resp) - assert newsession["path"] == "foo/nb1.py" - assert newsession["type"] == "file" - sid = newsession["id"] - await session_is_ready(sid) - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_console_session( - session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/abc123", type="console") - assert resp.code == 201 - newsession = j(resp) - assert newsession["path"] == "foo/abc123" - assert newsession["type"] == "console" - # Need to find a better solution to this. - sid = newsession["id"] - await session_is_ready(sid) - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_deprecated(session_client, jp_cleanup_subprocesses, jp_serverapp): - resp = await session_client.create_deprecated("foo/nb1.ipynb") - assert resp.code == 201 - newsession = j(resp) - assert newsession["path"] == "foo/nb1.ipynb" - assert newsession["type"] == "notebook" - assert newsession["notebook"]["path"] == "foo/nb1.ipynb" - # Need to find a better solution to this. - sid = newsession["id"] - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_with_kernel_id( - session_client, jp_fetch, jp_base_url, jp_cleanup_subprocesses, jp_serverapp -): - # create a new kernel - resp = await jp_fetch("https://github.com/api/kernels", method="POST", allow_nonstandard_methods=True) - kernel = j(resp) - - resp = await session_client.create("foo/nb1.ipynb", kernel_id=kernel["id"]) - assert resp.code == 201 - new_session = j(resp) - assert "id" in new_session - assert new_session["path"] == "foo/nb1.ipynb" - assert new_session["kernel"]["id"] == kernel["id"] - assert resp.headers["Location"] == url_path_join( - jp_base_url, "/api/sessions/{0}".format(new_session["id"]) - ) - - resp = await session_client.list() - sessions = j(resp) - assert len(sessions) == 1 - assert_session_equality(sessions[0], new_session) - - # Retrieve it - sid = new_session["id"] - resp = await session_client.get(sid) - got = j(resp) - assert_session_equality(got, new_session) - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_create_with_bad_kernel_id( - session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/nb1.py", type="file") - assert resp.code == 201 - newsession = j(resp) - sid = newsession["id"] - await session_is_ready(sid) - - # TODO - assert newsession["path"] == "foo/nb1.py" - assert newsession["type"] == "file" - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_delete(session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready): - resp = await session_client.create("foo/nb1.ipynb") - - newsession = j(resp) - sid = newsession["id"] - await session_is_ready(sid) - - resp = await session_client.delete(sid) - assert resp.code == 204 - - resp = await session_client.list() - sessions = j(resp) - assert sessions == [] - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await session_client.get(sid) - assert expected_http_error(e, 404) - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_modify_path(session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready): - resp = await session_client.create("foo/nb1.ipynb") - newsession = j(resp) - sid = newsession["id"] - await session_is_ready(sid) - - resp = await session_client.modify_path(sid, "nb2.ipynb") - changed = j(resp) - assert changed["id"] == sid - assert changed["path"] == "nb2.ipynb" - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_modify_path_deprecated( - session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/nb1.ipynb") - newsession = j(resp) - sid = newsession["id"] - await session_is_ready(sid) - - resp = await session_client.modify_path_deprecated(sid, "nb2.ipynb") - changed = j(resp) - assert changed["id"] == sid - assert changed["notebook"]["path"] == "nb2.ipynb" - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_modify_type(session_client, jp_cleanup_subprocesses, jp_serverapp, session_is_ready): - resp = await session_client.create("foo/nb1.ipynb") - newsession = j(resp) - sid = newsession["id"] - await session_is_ready(sid) - - resp = await session_client.modify_type(sid, "console") - changed = j(resp) - assert changed["id"] == sid - assert changed["type"] == "console" - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_modify_kernel_name( - session_client, jp_fetch, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/nb1.ipynb") - before = j(resp) - sid = before["id"] - await session_is_ready(sid) - - resp = await session_client.modify_kernel_name(sid, before["kernel"]["name"]) - after = j(resp) - assert after["id"] == sid - assert after["path"] == before["path"] - assert after["type"] == before["type"] - assert after["kernel"]["id"] != before["kernel"]["id"] - - # check kernel list, to be sure previous kernel was cleaned up - resp = await jp_fetch("https://github.com/api/kernels", method="GET") - kernel_list = j(resp) - after["kernel"].pop("last_activity") - [k.pop("last_activity") for k in kernel_list] - if not getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - assert kernel_list == [after["kernel"]] - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_modify_kernel_id( - session_client, jp_fetch, jp_cleanup_subprocesses, jp_serverapp, session_is_ready -): - resp = await session_client.create("foo/nb1.ipynb") - before = j(resp) - sid = before["id"] - await session_is_ready(sid) - - # create a new kernel - resp = await jp_fetch("https://github.com/api/kernels", method="POST", allow_nonstandard_methods=True) - kernel = j(resp) - - # Attach our session to the existing kernel - resp = await session_client.modify_kernel_id(sid, kernel["id"]) - after = j(resp) - assert after["id"] == sid - assert after["path"] == before["path"] - assert after["type"] == before["type"] - assert after["kernel"]["id"] != before["kernel"]["id"] - assert after["kernel"]["id"] == kernel["id"] - - # check kernel list, to be sure previous kernel was cleaned up - resp = await jp_fetch("https://github.com/api/kernels", method="GET") - kernel_list = j(resp) - - kernel.pop("last_activity") - [k.pop("last_activity") for k in kernel_list] - if not getattr(jp_serverapp.kernel_manager, "use_pending_kernels", False): - assert kernel_list == [kernel] - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() - - -@pytest.mark.timeout(TEST_TIMEOUT) -async def test_restart_kernel( - session_client, jp_base_url, jp_fetch, jp_ws_fetch, jp_cleanup_subprocesses, session_is_ready -): - # Create a session. - resp = await session_client.create("foo/nb1.ipynb") - assert resp.code == 201 - new_session = j(resp) - assert "id" in new_session - assert new_session["path"] == "foo/nb1.ipynb" - assert new_session["type"] == "notebook" - assert resp.headers["Location"] == url_path_join( - jp_base_url, "/api/sessions/", new_session["id"] - ) - sid = new_session["id"] - await session_is_ready(sid) - - kid = new_session["kernel"]["id"] - - # Get kernel info - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 0 - - # Open a websocket connection. - ws = await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - # Test that it was opened. - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 1 - - # Restart kernel - r = await jp_fetch( - "api", "kernels", kid, "restart", method="POST", allow_nonstandard_methods=True - ) - restarted_kernel = json.loads(r.body.decode()) - assert restarted_kernel["id"] == kid - - # Close/open websocket - ws.close() - # give it some time to close on the other side: - for i in range(10): - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - if model["connections"] > 0: - time.sleep(0.1) - else: - break - - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 0 - - # Open a websocket connection. - await jp_ws_fetch("https://github.com/api", "kernels", kid, "channels") - - r = await jp_fetch("https://github.com/api", "kernels", kid, method="GET") - model = json.loads(r.body.decode()) - assert model["connections"] == 1 - - # Need to find a better solution to this. - await jp_cleanup_subprocesses() diff --git a/server/jupyter_server/tests/services/sessions/test_manager.py b/server/jupyter_server/tests/services/sessions/test_manager.py deleted file mode 100644 index f0142be..0000000 --- a/server/jupyter_server/tests/services/sessions/test_manager.py +++ /dev/null @@ -1,365 +0,0 @@ -import pytest -from tornado import web -from traitlets import TraitError - -from jupyter_server._tz import isoformat -from jupyter_server._tz import utcnow -from jupyter_server.services.contents.manager import ContentsManager -from jupyter_server.services.kernels.kernelmanager import MappingKernelManager -from jupyter_server.services.sessions.sessionmanager import SessionManager - - -class DummyKernel(object): - def __init__(self, kernel_name="python"): - self.kernel_name = kernel_name - - -dummy_date = utcnow() -dummy_date_s = isoformat(dummy_date) - - -class DummyMKM(MappingKernelManager): - """MappingKernelManager interface that doesn't start kernels, for testing""" - - def __init__(self, *args, **kwargs): - super(DummyMKM, self).__init__(*args, **kwargs) - self.id_letters = iter("ABCDEFGHIJK") - - def _new_id(self): - return next(self.id_letters) - - async def start_kernel(self, kernel_id=None, path=None, kernel_name="python", **kwargs): - kernel_id = kernel_id or self._new_id() - k = self._kernels[kernel_id] = DummyKernel(kernel_name=kernel_name) - self._kernel_connections[kernel_id] = 0 - k.last_activity = dummy_date - k.execution_state = "idle" - return kernel_id - - async def shutdown_kernel(self, kernel_id, now=False): - del self._kernels[kernel_id] - - -@pytest.fixture -def session_manager(): - return SessionManager(kernel_manager=DummyMKM(), contents_manager=ContentsManager()) - - -async def create_multiple_sessions(session_manager, *kwargs_list): - sessions = [] - for kwargs in kwargs_list: - kwargs.setdefault("type", "notebook") - session = await session_manager.create_session(**kwargs) - sessions.append(session) - return sessions - - -async def test_get_session(session_manager): - session = await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="bar", type="notebook" - ) - session_id = session["id"] - model = await session_manager.get_session(session_id=session_id) - expected = { - "id": session_id, - "path": "/path/to/test.ipynb", - "notebook": {"path": "/path/to/test.ipynb", "name": None}, - "type": "notebook", - "name": None, - "kernel": { - "id": "A", - "name": "bar", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - } - assert model == expected - - -async def test_bad_get_session(session_manager): - session = await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="foo", type="notebook" - ) - with pytest.raises(TypeError): - await session_manager.get_session(bad_id=session["id"]) - - -async def test_get_session_dead_kernel(session_manager): - session = await session_manager.create_session( - path="/path/to/1/test1.ipynb", kernel_name="python", type="notebook" - ) - # Kill the kernel - await session_manager.kernel_manager.shutdown_kernel(session["kernel"]["id"]) - with pytest.raises(web.HTTPError): - await session_manager.get_session(session_id=session["id"]) - # no session left - listed = await session_manager.list_sessions() - assert listed == [] - - -async def test_list_session(session_manager): - sessions = await create_multiple_sessions( - session_manager, - dict(path="/path/to/1/test1.ipynb", kernel_name="python"), - dict(path="/path/to/2/test2.py", type="file", kernel_name="python"), - dict(path="/path/to/3", name="foo", type="console", kernel_name="python"), - ) - sessions = await session_manager.list_sessions() - expected = [ - { - "id": sessions[0]["id"], - "path": "/path/to/1/test1.ipynb", - "type": "notebook", - "notebook": {"path": "/path/to/1/test1.ipynb", "name": None}, - "name": None, - "kernel": { - "id": "A", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - }, - { - "id": sessions[1]["id"], - "path": "/path/to/2/test2.py", - "type": "file", - "name": None, - "kernel": { - "id": "B", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - }, - { - "id": sessions[2]["id"], - "path": "/path/to/3", - "type": "console", - "name": "foo", - "kernel": { - "id": "C", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - }, - ] - assert sessions == expected - - -async def test_list_sessions_dead_kernel(session_manager): - sessions = await create_multiple_sessions( - session_manager, - dict(path="/path/to/1/test1.ipynb", kernel_name="python"), - dict(path="/path/to/2/test2.ipynb", kernel_name="python"), - ) - # kill one of the kernels - await session_manager.kernel_manager.shutdown_kernel(sessions[0]["kernel"]["id"]) - listed = await session_manager.list_sessions() - expected = [ - { - "id": sessions[1]["id"], - "path": "/path/to/2/test2.ipynb", - "type": "notebook", - "name": None, - "notebook": {"path": "/path/to/2/test2.ipynb", "name": None}, - "kernel": { - "id": "B", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - } - ] - assert listed == expected - - -async def test_update_session(session_manager): - session = await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="julia", type="notebook" - ) - session_id = session["id"] - await session_manager.update_session(session_id, path="/path/to/new_name.ipynb") - model = await session_manager.get_session(session_id=session_id) - expected = { - "id": session_id, - "path": "/path/to/new_name.ipynb", - "type": "notebook", - "name": None, - "notebook": {"path": "/path/to/new_name.ipynb", "name": None}, - "kernel": { - "id": "A", - "name": "julia", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - } - assert model == expected - - -async def test_bad_update_session(session_manager): - # try to update a session with a bad keyword ~ raise error - session = await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="ir", type="notegbook" - ) - session_id = session["id"] - with pytest.raises(TypeError): - await session_manager.update_session( - session_id=session_id, bad_kw="test.ipynb" - ) # Bad keyword - - -async def test_delete_session(session_manager): - sessions = await create_multiple_sessions( - session_manager, - dict(path="/path/to/1/test1.ipynb", kernel_name="python"), - dict(path="/path/to/2/test2.ipynb", kernel_name="python"), - dict(path="/path/to/3", name="foo", type="console", kernel_name="python"), - ) - await session_manager.delete_session(sessions[1]["id"]) - new_sessions = await session_manager.list_sessions() - expected = [ - { - "id": sessions[0]["id"], - "path": "/path/to/1/test1.ipynb", - "type": "notebook", - "name": None, - "notebook": {"path": "/path/to/1/test1.ipynb", "name": None}, - "kernel": { - "id": "A", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - }, - { - "id": sessions[2]["id"], - "type": "console", - "path": "/path/to/3", - "name": "foo", - "kernel": { - "id": "C", - "name": "python", - "connections": 0, - "last_activity": dummy_date_s, - "execution_state": "idle", - }, - }, - ] - assert new_sessions == expected - - -async def test_bad_delete_session(session_manager): - # try to delete a session that doesn't exist ~ raise error - await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="python", type="notebook" - ) - with pytest.raises(TypeError): - await session_manager.delete_session(bad_kwarg="23424") # Bad keyword - with pytest.raises(web.HTTPError): - await session_manager.delete_session(session_id="23424") # nonexistent - - -async def test_bad_database_filepath(jp_runtime_dir): - kernel_manager = DummyMKM() - - # Try to write to a path that's a directory, not a file. - path_id_directory = str(jp_runtime_dir) - # Should raise an error because the path is a directory. - with pytest.raises(TraitError) as err: - SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(path_id_directory), - ) - - # Try writing to file that's not a valid SQLite 3 database file. - non_db_file = jp_runtime_dir.joinpath("non_db_file.db") - non_db_file.write_bytes(b"this is a bad file") - - # Should raise an error because the file doesn't - # start with an SQLite database file header. - with pytest.raises(TraitError) as err: - SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(non_db_file), - ) - - -async def test_good_database_filepath(jp_runtime_dir): - kernel_manager = DummyMKM() - - # Try writing to an empty file. - empty_file = jp_runtime_dir.joinpath("empty.db") - empty_file.write_bytes(b"") - - session_manager = SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(empty_file), - ) - - await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="python", type="notebook" - ) - # Assert that the database file exists - assert empty_file.exists() - - # Close the current session manager - del session_manager - - # Try writing to a file that already exists. - session_manager = SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(empty_file), - ) - - assert session_manager.database_filepath == str(empty_file) - - -async def test_session_persistence(jp_runtime_dir): - session_db_path = jp_runtime_dir.joinpath("test-session.db") - # Kernel manager needs to persist. - kernel_manager = DummyMKM() - - # Initialize a session and start a connection. - # This should create the session database the first time. - session_manager = SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(session_db_path), - ) - - session = await session_manager.create_session( - path="/path/to/test.ipynb", kernel_name="python", type="notebook" - ) - - # Assert that the database file exists - assert session_db_path.exists() - - with open(session_db_path, "rb") as f: - header = f.read(100) - - assert header.startswith(b"SQLite format 3") - - # Close the current session manager - del session_manager - - # Get a new session_manager - session_manager = SessionManager( - kernel_manager=kernel_manager, - contents_manager=ContentsManager(), - database_filepath=str(session_db_path), - ) - - # Assert that the session database persists. - session = await session_manager.get_session(session_id=session["id"]) diff --git a/server/jupyter_server/tests/test_config_manager.py b/server/jupyter_server/tests/test_config_manager.py deleted file mode 100644 index 5329ca8..0000000 --- a/server/jupyter_server/tests/test_config_manager.py +++ /dev/null @@ -1,50 +0,0 @@ -import json -import os - -from jupyter_server.config_manager import BaseJSONConfigManager - - -def test_json(tmp_path): - tmpdir = str(tmp_path) - - root_data = dict(a=1, x=2, nest={"a": 1, "x": 2}) - with open(os.path.join(tmpdir, "foo.json"), "w") as f: - json.dump(root_data, f) - # also make a foo.d/ directory with multiple json files - os.makedirs(os.path.join(tmpdir, "foo.d")) - with open(os.path.join(tmpdir, "foo.d", "a.json"), "w") as f: - json.dump(dict(a=2, b=1, nest={"a": 2, "b": 1}), f) - with open(os.path.join(tmpdir, "foo.d", "b.json"), "w") as f: - json.dump(dict(a=3, b=2, c=3, nest={"a": 3, "b": 2, "c": 3}, only_in_b={"x": 1}), f) - manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False) - data = manager.get("foo") - assert "a" in data - assert "x" in data - assert "b" not in data - assert "c" not in data - assert data["a"] == 1 - assert "x" in data["nest"] - # if we write it out, it also shouldn't pick up the subdirectoy - manager.set("foo", data) - data = manager.get("foo") - assert data == root_data - - manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=True) - data = manager.get("foo") - assert "a" in data - assert "b" in data - assert "c" in data - # files should be read in order foo.d/a.json foo.d/b.json foo.json - assert data["a"] == 1 - assert data["b"] == 2 - assert data["c"] == 3 - assert data["nest"]["a"] == 1 - assert data["nest"]["b"] == 2 - assert data["nest"]["c"] == 3 - assert data["nest"]["x"] == 2 - - # when writing out, we don't want foo.d/*.json data to be included in the root foo.json - manager.set("foo", data) - manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False) - data = manager.get("foo") - assert data == root_data diff --git a/server/jupyter_server/tests/test_files.py b/server/jupyter_server/tests/test_files.py deleted file mode 100644 index c592d89..0000000 --- a/server/jupyter_server/tests/test_files.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -from pathlib import Path - -import pytest -import tornado -from nbformat import writes -from nbformat.v4 import new_code_cell -from nbformat.v4 import new_markdown_cell -from nbformat.v4 import new_notebook -from nbformat.v4 import new_output - -from .utils import expected_http_error - - -@pytest.fixture( - params=[ - [False, ["ÃĨ b"]], - [False, ["ÃĨ b", "ç. d"]], - [True, [".ÃĨ b"]], - [True, ["ÃĨ b", ".ç d"]], - ] -) -def maybe_hidden(request): - return request.param - - -async def fetch_expect_200(jp_fetch, *path_parts): - r = await jp_fetch("https://github.com/files", *path_parts, method="GET") - assert r.body.decode() == path_parts[-1], (path_parts, r.body) - - -async def fetch_expect_404(jp_fetch, *path_parts): - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/files", *path_parts, method="GET") - assert expected_http_error(e, 404), [path_parts, e] - - -async def test_hidden_files(jp_fetch, jp_serverapp, jp_root_dir, maybe_hidden): - is_hidden, path_parts = maybe_hidden - path = Path(jp_root_dir, *path_parts) - path.mkdir(parents=True, exist_ok=True) - - foos = ["foo", ".foo"] - for foo in foos: - (path / foo).write_text(foo) - - if is_hidden: - for foo in foos: - await fetch_expect_404(jp_fetch, *path_parts, foo) - else: - await fetch_expect_404(jp_fetch, *path_parts, ".foo") - await fetch_expect_200(jp_fetch, *path_parts, "foo") - - jp_serverapp.contents_manager.allow_hidden = True - - for foo in foos: - await fetch_expect_200(jp_fetch, *path_parts, foo) - - -async def test_contents_manager(jp_fetch, jp_serverapp, jp_root_dir): - """make sure ContentsManager returns right files (ipynb, bin, txt).""" - nb = new_notebook( - cells=[ - new_markdown_cell("Created by test Âŗ"), - new_code_cell( - "print(2*6)", - outputs=[ - new_output("stream", text="12"), - ], - ), - ] - ) - jp_root_dir.joinpath("testnb.ipynb").write_text(writes(nb, version=4), encoding="utf-8") - jp_root_dir.joinpath("test.bin").write_bytes(b"\xff" + os.urandom(5)) - jp_root_dir.joinpath("test.txt").write_text("foobar") - - r = await jp_fetch("https://github.com/files/testnb.ipynb", method="GET") - assert r.code == 200 - assert "print(2*6)" in r.body.decode("utf-8") - - r = await jp_fetch("https://github.com/files/test.bin", method="GET") - assert r.code == 200 - assert r.headers["content-type"] == "application/octet-stream" - assert r.body[:1] == b"\xff" - assert len(r.body) == 6 - - r = await jp_fetch("https://github.com/files/test.txt", method="GET") - assert r.code == 200 - assert r.headers["content-type"] == "text/plain; charset=UTF-8" - assert r.body.decode() == "foobar" - - -async def test_download(jp_fetch, jp_serverapp, jp_root_dir): - text = "hello" - jp_root_dir.joinpath("test.txt").write_text(text) - - r = await jp_fetch("https://github.com/files", "test.txt", method="GET") - disposition = r.headers.get("Content-Disposition", "") - assert "attachment" not in disposition - - r = await jp_fetch("https://github.com/files", "test.txt", method="GET", params={"download": True}) - disposition = r.headers.get("Content-Disposition", "") - assert "attachment" in disposition - assert "filename*=utf-8''test.txt" in disposition - - -async def test_old_files_redirect(jp_fetch, jp_serverapp, jp_root_dir): - """pre-2.0 'files/' prefixed links are properly redirected""" - jp_root_dir.joinpath("files").mkdir(parents=True, exist_ok=True) - jp_root_dir.joinpath("sub", "files").mkdir(parents=True, exist_ok=True) - - for prefix in ("", "sub"): - jp_root_dir.joinpath(prefix, "files", "f1.txt").write_text(prefix + "/files/f1") - jp_root_dir.joinpath(prefix, "files", "f2.txt").write_text(prefix + "/files/f2") - jp_root_dir.joinpath(prefix, "f2.txt").write_text(prefix + "/f2") - jp_root_dir.joinpath(prefix, "f3.txt").write_text(prefix + "/f3") - - # These depend on the tree handlers - # - # def test_download(self): - # rootdir = self.root_dir - - # text = 'hello' - # with open(pjoin(rootdir, 'test.txt'), 'w') as f: - # f.write(text) - - # r = self.request('GET', 'files/test.txt') - # disposition = r.headers.get('Content-Disposition', '') - # self.assertNotIn('attachment', disposition) - - # r = self.request('GET', 'files/test.txt?download=1') - # disposition = r.headers.get('Content-Disposition', '') - # self.assertIn('attachment', disposition) - # self.assertIn("filename*=utf-8''test.txt", disposition) diff --git a/server/jupyter_server/tests/test_gateway.py b/server/jupyter_server/tests/test_gateway.py deleted file mode 100644 index ec279f3..0000000 --- a/server/jupyter_server/tests/test_gateway.py +++ /dev/null @@ -1,411 +0,0 @@ -"""Test GatewayClient""" -import json -import os -import uuid -from datetime import datetime -from io import StringIO -from unittest.mock import patch - -import pytest -import tornado -from tornado.httpclient import HTTPRequest -from tornado.httpclient import HTTPResponse -from tornado.web import HTTPError - -from .utils import expected_http_error -from jupyter_server.gateway.managers import GatewayClient -from jupyter_server.utils import ensure_async - - -def generate_kernelspec(name): - argv_stanza = ["python", "-m", "ipykernel_launcher", "-f", "{connection_file}"] - spec_stanza = { - "spec": { - "argv": argv_stanza, - "env": {}, - "display_name": name, - "language": "python", - "interrupt_mode": "signal", - "metadata": {}, - } - } - kernelspec_stanza = {"name": name, "spec": spec_stanza, "resources": {}} - return kernelspec_stanza - - -# We'll mock up two kernelspecs - kspec_foo and kspec_bar -kernelspecs = { - "default": "kspec_foo", - "kernelspecs": { - "kspec_foo": generate_kernelspec("kspec_foo"), - "kspec_bar": generate_kernelspec("kspec_bar"), - }, -} - - -# maintain a dictionary of expected running kernels. Key = kernel_id, Value = model. -running_kernels = dict() - - -def generate_model(name): - """Generate a mocked kernel model. Caller is responsible for adding model to running_kernels dictionary.""" - dt = datetime.utcnow().isoformat() + "Z" - kernel_id = str(uuid.uuid4()) - model = { - "id": kernel_id, - "name": name, - "last_activity": str(dt), - "execution_state": "idle", - "connections": 1, - } - return model - - -async def mock_gateway_request(url, **kwargs): - method = "GET" - if kwargs["method"]: - method = kwargs["method"] - - request = HTTPRequest(url=url, **kwargs) - - endpoint = str(url) - - # Fetch all kernelspecs - if endpoint.endswith("/api/kernelspecs") and method == "GET": - response_buf = StringIO(json.dumps(kernelspecs)) - response = await ensure_async(HTTPResponse(request, 200, buffer=response_buf)) - return response - - # Fetch named kernelspec - if endpoint.rfind("/api/kernelspecs/") >= 0 and method == "GET": - requested_kernelspec = endpoint.rpartition("/")[2] - kspecs = kernelspecs.get("kernelspecs") - if requested_kernelspec in kspecs: - response_buf = StringIO(json.dumps(kspecs.get(requested_kernelspec))) - response = await ensure_async(HTTPResponse(request, 200, buffer=response_buf)) - return response - else: - raise HTTPError(404, message="Kernelspec does not exist: %s" % requested_kernelspec) - - # Create kernel - if endpoint.endswith("/api/kernels") and method == "POST": - json_body = json.loads(kwargs["body"]) - name = json_body.get("name") - env = json_body.get("env") - kspec_name = env.get("KERNEL_KSPEC_NAME") - assert name == kspec_name # Ensure that KERNEL_ env values get propagated - model = generate_model(name) - running_kernels[model.get("id")] = model # Register model as a running kernel - response_buf = StringIO(json.dumps(model)) - response = await ensure_async(HTTPResponse(request, 201, buffer=response_buf)) - return response - - # Fetch list of running kernels - if endpoint.endswith("/api/kernels") and method == "GET": - kernels = [] - for kernel_id in running_kernels.keys(): - model = running_kernels.get(kernel_id) - kernels.append(model) - response_buf = StringIO(json.dumps(kernels)) - response = await ensure_async(HTTPResponse(request, 200, buffer=response_buf)) - return response - - # Interrupt or restart existing kernel - if endpoint.rfind("/api/kernels/") >= 0 and method == "POST": - requested_kernel_id, sep, action = endpoint.rpartition("/api/kernels/")[2].rpartition("/") - - if action == "interrupt": - if requested_kernel_id in running_kernels: - response = await ensure_async(HTTPResponse(request, 204)) - return response - else: - raise HTTPError(404, message="Kernel does not exist: %s" % requested_kernel_id) - elif action == "restart": - if requested_kernel_id in running_kernels: - response_buf = StringIO(json.dumps(running_kernels.get(requested_kernel_id))) - response = await ensure_async(HTTPResponse(request, 204, buffer=response_buf)) - return response - else: - raise HTTPError(404, message="Kernel does not exist: %s" % requested_kernel_id) - else: - raise HTTPError(404, message="Bad action detected: %s" % action) - - # Shutdown existing kernel - if endpoint.rfind("/api/kernels/") >= 0 and method == "DELETE": - requested_kernel_id = endpoint.rpartition("/")[2] - running_kernels.pop( - requested_kernel_id - ) # Simulate shutdown by removing kernel from running set - response = await ensure_async(HTTPResponse(request, 204)) - return response - - # Fetch existing kernel - if endpoint.rfind("/api/kernels/") >= 0 and method == "GET": - requested_kernel_id = endpoint.rpartition("/")[2] - if requested_kernel_id in running_kernels: - response_buf = StringIO(json.dumps(running_kernels.get(requested_kernel_id))) - response = await ensure_async(HTTPResponse(request, 200, buffer=response_buf)) - return response - else: - raise HTTPError(404, message="Kernel does not exist: %s" % requested_kernel_id) - - -mocked_gateway = patch("jupyter_server.gateway.managers.gateway_request", mock_gateway_request) -mock_gateway_url = "http://mock-gateway-server:8889/" -mock_http_user = "alice" - - -@pytest.fixture -def init_gateway(monkeypatch): - """Initializes the server for use as a gateway client.""" - # Clear the singleton first since previous tests may not have used a gateway. - GatewayClient.clear_instance() - monkeypatch.setenv("JUPYTER_GATEWAY_URL", mock_gateway_url) - monkeypatch.setenv("JUPYTER_GATEWAY_HTTP_USER", mock_http_user) - monkeypatch.setenv("JUPYTER_GATEWAY_REQUEST_TIMEOUT", "44.4") - monkeypatch.setenv("JUPYTER_GATEWAY_CONNECT_TIMEOUT", "44.4") - yield - GatewayClient.clear_instance() - - -async def test_gateway_env_options(init_gateway, jp_serverapp): - assert jp_serverapp.gateway_config.gateway_enabled is True - assert jp_serverapp.gateway_config.url == mock_gateway_url - assert jp_serverapp.gateway_config.http_user == mock_http_user - assert ( - jp_serverapp.gateway_config.connect_timeout == jp_serverapp.gateway_config.request_timeout - ) - assert jp_serverapp.gateway_config.connect_timeout == 44.4 - - GatewayClient.instance().init_static_args() - assert GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == int( - jp_serverapp.gateway_config.request_timeout - ) - - -async def test_gateway_cli_options(jp_configurable_serverapp): - argv = [ - "--gateway-url=" + mock_gateway_url, - "--GatewayClient.http_user=" + mock_http_user, - "--GatewayClient.connect_timeout=44.4", - "--GatewayClient.request_timeout=96.0", - ] - - GatewayClient.clear_instance() - app = jp_configurable_serverapp(argv=argv) - - assert app.gateway_config.gateway_enabled is True - assert app.gateway_config.url == mock_gateway_url - assert app.gateway_config.http_user == mock_http_user - assert app.gateway_config.connect_timeout == 44.4 - assert app.gateway_config.request_timeout == 96.0 - GatewayClient.instance().init_static_args() - assert ( - GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == 96 - ) # Ensure KLT gets set from request-timeout - GatewayClient.clear_instance() - - -async def test_gateway_class_mappings(init_gateway, jp_serverapp): - # Ensure appropriate class mappings are in place. - assert jp_serverapp.kernel_manager_class.__name__ == "GatewayMappingKernelManager" - assert jp_serverapp.session_manager_class.__name__ == "GatewaySessionManager" - assert jp_serverapp.kernel_spec_manager_class.__name__ == "GatewayKernelSpecManager" - - -async def test_gateway_get_kernelspecs(init_gateway, jp_fetch): - # Validate that kernelspecs come from gateway. - with mocked_gateway: - r = await jp_fetch("https://github.com/api", "kernelspecs", method="GET") - assert r.code == 200 - content = json.loads(r.body.decode("utf-8")) - kspecs = content.get("kernelspecs") - assert len(kspecs) == 2 - assert kspecs.get("kspec_bar").get("name") == "kspec_bar" - - -async def test_gateway_get_named_kernelspec(init_gateway, jp_fetch): - # Validate that a specific kernelspec can be retrieved from gateway (and an invalid spec can't) - with mocked_gateway: - r = await jp_fetch("https://github.com/api", "kernelspecs", "kspec_foo", method="GET") - assert r.code == 200 - kspec_foo = json.loads(r.body.decode("utf-8")) - assert kspec_foo.get("name") == "kspec_foo" - - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/api", "kernelspecs", "no_such_spec", method="GET") - assert expected_http_error(e, 404) - - -async def test_gateway_session_lifecycle(init_gateway, jp_root_dir, jp_fetch): - # Validate session lifecycle functions; create and delete. - - # create - session_id, kernel_id = await create_session(jp_root_dir, jp_fetch, "kspec_foo") - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # interrupt - await interrupt_kernel(jp_fetch, kernel_id) - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # restart - await restart_kernel(jp_fetch, kernel_id) - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # delete - await delete_session(jp_fetch, session_id) - assert await is_kernel_running(jp_fetch, kernel_id) is False - - -async def test_gateway_kernel_lifecycle(init_gateway, jp_fetch): - # Validate kernel lifecycle functions; create, interrupt, restart and delete. - - # create - kernel_id = await create_kernel(jp_fetch, "kspec_bar") - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # interrupt - await interrupt_kernel(jp_fetch, kernel_id) - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # restart - await restart_kernel(jp_fetch, kernel_id) - - # ensure kernel still considered running - assert await is_kernel_running(jp_fetch, kernel_id) is True - - # delete - await delete_kernel(jp_fetch, kernel_id) - assert await is_kernel_running(jp_fetch, kernel_id) is False - - -# -# Test methods below... -# -async def create_session(root_dir, jp_fetch, kernel_name): - """Creates a session for a kernel. The session is created against the server - which then uses the gateway for kernel management. - """ - with mocked_gateway: - nb_path = root_dir / "testgw.ipynb" - body = json.dumps( - {"path": str(nb_path), "type": "notebook", "kernel": {"name": kernel_name}} - ) - - # add a KERNEL_ value to the current env and we'll ensure that that value exists in the mocked method - os.environ["KERNEL_KSPEC_NAME"] = kernel_name - - # Create the kernel... (also tests get_kernel) - r = await jp_fetch("https://github.com/api", "sessions", method="POST", body=body) - assert r.code == 201 - model = json.loads(r.body.decode("utf-8")) - assert model.get("path") == str(nb_path) - kernel_id = model.get("kernel").get("id") - # ensure its in the running_kernels and name matches. - running_kernel = running_kernels.get(kernel_id) - assert kernel_id == running_kernel.get("id") - assert model.get("kernel").get("name") == running_kernel.get("name") - session_id = model.get("id") - - # restore env - os.environ.pop("KERNEL_KSPEC_NAME") - return session_id, kernel_id - - -async def delete_session(jp_fetch, session_id): - """Deletes a session corresponding to the given session id.""" - with mocked_gateway: - # Delete the session (and kernel) - r = await jp_fetch("https://github.com/api", "sessions", session_id, method="DELETE") - assert r.code == 204 - assert r.reason == "No Content" - - -async def is_kernel_running(jp_fetch, kernel_id): - """Issues request to get the set of running kernels""" - with mocked_gateway: - # Get list of running kernels - r = await jp_fetch("https://github.com/api", "kernels", method="GET") - assert r.code == 200 - kernels = json.loads(r.body.decode("utf-8")) - assert len(kernels) == len(running_kernels) - for model in kernels: - if model.get("id") == kernel_id: - return True - return False - - -async def create_kernel(jp_fetch, kernel_name): - """Issues request to retart the given kernel""" - with mocked_gateway: - body = json.dumps({"name": kernel_name}) - - # add a KERNEL_ value to the current env and we'll ensure that that value exists in the mocked method - os.environ["KERNEL_KSPEC_NAME"] = kernel_name - - r = await jp_fetch("https://github.com/api", "kernels", method="POST", body=body) - assert r.code == 201 - model = json.loads(r.body.decode("utf-8")) - kernel_id = model.get("id") - # ensure its in the running_kernels and name matches. - running_kernel = running_kernels.get(kernel_id) - assert kernel_id == running_kernel.get("id") - assert model.get("name") == kernel_name - - # restore env - os.environ.pop("KERNEL_KSPEC_NAME") - return kernel_id - - -async def interrupt_kernel(jp_fetch, kernel_id): - """Issues request to interrupt the given kernel""" - with mocked_gateway: - r = await jp_fetch( - "api", - "kernels", - kernel_id, - "interrupt", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 204 - assert r.reason == "No Content" - - -async def restart_kernel(jp_fetch, kernel_id): - """Issues request to retart the given kernel""" - with mocked_gateway: - r = await jp_fetch( - "api", - "kernels", - kernel_id, - "restart", - method="POST", - allow_nonstandard_methods=True, - ) - assert r.code == 200 - model = json.loads(r.body.decode("utf-8")) - restarted_kernel_id = model.get("id") - # ensure its in the running_kernels and name matches. - running_kernel = running_kernels.get(restarted_kernel_id) - assert restarted_kernel_id == running_kernel.get("id") - assert model.get("name") == running_kernel.get("name") - - -async def delete_kernel(jp_fetch, kernel_id): - """Deletes kernel corresponding to the given kernel id.""" - with mocked_gateway: - # Delete the session (and kernel) - r = await jp_fetch("https://github.com/api", "kernels", kernel_id, method="DELETE") - assert r.code == 204 - assert r.reason == "No Content" diff --git a/server/jupyter_server/tests/test_paths.py b/server/jupyter_server/tests/test_paths.py deleted file mode 100644 index 0789be4..0000000 --- a/server/jupyter_server/tests/test_paths.py +++ /dev/null @@ -1,68 +0,0 @@ -import re - -import pytest -import tornado - -from jupyter_server.base.handlers import path_regex -from jupyter_server.utils import url_path_join - -# build regexps that tornado uses: -path_pat = re.compile("^" + "/x%s" % path_regex + "$") - - -def test_path_regex(): - for path in ( - "/x", - "/x/", - "/x/foo", - "/x/foo.ipynb", - "/x/foo/bar", - "/x/foo/bar.txt", - ): - assert re.match(path_pat, path) - - -def test_path_regex_bad(): - for path in ( - "/xfoo", - "/xfoo/", - "/xfoo/bar", - "/xfoo/bar/", - "/x/foo/bar/", - "/x//foo", - "/y", - "/y/x/foo", - ): - assert re.match(path_pat, path) is None - - -@pytest.mark.parametrize( - "uri,expected", - [ - ("/notebooks/mynotebook/", "/notebooks/mynotebook"), - ("////foo///", "/foo"), - ("//example.com/", "/example.com"), - ("/has/param/?hasparam=true", "/has/param?hasparam=true"), - ], -) -async def test_trailing_slash( - jp_ensure_app_fixture, - uri, - expected, - http_server_client, - jp_auth_header, - jp_base_url, -): - # http_server_client raises an exception when follow_redirects=False - with pytest.raises(tornado.httpclient.HTTPClientError) as err: - await http_server_client.fetch( - url_path_join(jp_base_url, uri), - headers=jp_auth_header, - request_timeout=20, - follow_redirects=False, - ) - # Capture the response from the raised exception value. - response = err.value.response - assert response.code == 302 - assert "Location" in response.headers - assert response.headers["Location"] == url_path_join(jp_base_url, expected) diff --git a/server/jupyter_server/tests/test_serialize.py b/server/jupyter_server/tests/test_serialize.py deleted file mode 100644 index 56314df..0000000 --- a/server/jupyter_server/tests/test_serialize.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Test serialize/deserialize messages with buffers""" -import os - -from jupyter_client.session import Session - -from jupyter_server.base.zmqhandlers import deserialize_binary_message -from jupyter_server.base.zmqhandlers import serialize_binary_message - - -def test_serialize_binary(): - s = Session() - msg = s.msg("data_pub", content={"a": "b"}) - msg["buffers"] = [memoryview(os.urandom(3)) for i in range(3)] - bmsg = serialize_binary_message(msg) - assert isinstance(bmsg, bytes) - - -def test_deserialize_binary(): - s = Session() - msg = s.msg("data_pub", content={"a": "b"}) - msg["buffers"] = [memoryview(os.urandom(2)) for i in range(3)] - bmsg = serialize_binary_message(msg) - msg2 = deserialize_binary_message(bmsg) - assert msg2 == msg diff --git a/server/jupyter_server/tests/test_serverapp.py b/server/jupyter_server/tests/test_serverapp.py deleted file mode 100644 index 3808eb4..0000000 --- a/server/jupyter_server/tests/test_serverapp.py +++ /dev/null @@ -1,338 +0,0 @@ -import getpass -import logging -import os -import pathlib -from unittest.mock import patch - -import pytest -from jupyter_core.application import NoStart -from traitlets import TraitError -from traitlets.tests.utils import check_help_all_output - -from jupyter_server.auth.security import passwd_check -from jupyter_server.serverapp import JupyterPasswordApp -from jupyter_server.serverapp import list_running_servers -from jupyter_server.serverapp import ServerApp - - -def test_help_output(): - """jupyter server --help-all works""" - check_help_all_output("jupyter_server") - - -def test_server_info_file(tmp_path, jp_configurable_serverapp): - app = jp_configurable_serverapp(log=logging.getLogger()) - - app.write_server_info_file() - servers = list(list_running_servers(app.runtime_dir)) - - assert len(servers) == 1 - sinfo = servers[0] - - assert sinfo["port"] == app.port - assert sinfo["url"] == app.connection_url - assert sinfo["version"] == app.version - - app.remove_server_info_file() - - assert list(list_running_servers(app.runtime_dir)) == [] - app.remove_server_info_file - - -def test_root_dir(tmp_path, jp_configurable_serverapp): - app = jp_configurable_serverapp(root_dir=str(tmp_path)) - assert app.root_dir == str(tmp_path) - - -# Build a list of invalid paths -@pytest.fixture(params=[("notebooks",), ("root", "dir", "is", "missing"), ("test.txt",)]) -def invalid_root_dir(tmp_path, request): - path = tmp_path.joinpath(*request.param) - # If the path is a file, create it. - if os.path.splitext(str(path))[1] != "": - path.write_text("") - return str(path) - - -def test_invalid_root_dir(invalid_root_dir, jp_configurable_serverapp): - app = jp_configurable_serverapp() - with pytest.raises(TraitError): - app.root_dir = invalid_root_dir - - -@pytest.fixture(params=[("/",), ("first-level",), ("first-level", "second-level")]) -def valid_root_dir(tmp_path, request): - path = tmp_path.joinpath(*request.param) - if not path.exists(): - # Create path in temporary directory - path.mkdir(parents=True) - return str(path) - - -def test_valid_root_dir(valid_root_dir, jp_configurable_serverapp): - app = jp_configurable_serverapp(root_dir=valid_root_dir) - root_dir = valid_root_dir - # If nested path, the last slash should - # be stripped by the root_dir trait. - if root_dir != "/": - root_dir = valid_root_dir.rstrip("/") - assert app.root_dir == root_dir - - -def test_generate_config(tmp_path, jp_configurable_serverapp): - app = jp_configurable_serverapp(config_dir=str(tmp_path)) - app.initialize(["--generate-config", "--allow-root"]) - with pytest.raises(NoStart): - app.start() - assert tmp_path.joinpath("jupyter_server_config.py").exists() - - -def test_server_password(tmp_path, jp_configurable_serverapp): - password = "secret" - with patch.dict("os.environ", {"JUPYTER_CONFIG_DIR": str(tmp_path)}), patch.object( - getpass, "getpass", return_value=password - ): - app = JupyterPasswordApp(log_level=logging.ERROR) - app.initialize([]) - app.start() - sv = jp_configurable_serverapp() - sv.load_config_file() - assert sv.password != "" - passwd_check(sv.password, password) - - -def test_list_running_servers(jp_serverapp, jp_web_app): - servers = list(list_running_servers(jp_serverapp.runtime_dir)) - assert len(servers) >= 1 - - -@pytest.fixture -def prefix_path(jp_root_dir, tmp_path): - """If a given path is prefixed with the literal - strings `/jp_root_dir` or `/tmp_path`, replace those - strings with these fixtures. - - Returns a pathlib Path object. - """ - - def _inner(rawpath): - path = pathlib.PurePosixPath(rawpath) - if rawpath.startswith("/jp_root_dir"): - path = jp_root_dir.joinpath(*path.parts[2:]) - elif rawpath.startswith("/tmp_path"): - path = tmp_path.joinpath(*path.parts[2:]) - return pathlib.Path(path) - - return _inner - - -@pytest.mark.parametrize( - "root_dir,file_to_run,expected_output", - [ - (None, "notebook.ipynb", "notebook.ipynb"), - (None, "/tmp_path/path/to/notebook.ipynb", "notebook.ipynb"), - ("/jp_root_dir", "/tmp_path/path/to/notebook.ipynb", SystemExit), - ("/tmp_path", "/tmp_path/path/to/notebook.ipynb", "path/to/notebook.ipynb"), - ("/jp_root_dir", "notebook.ipynb", "notebook.ipynb"), - ("/jp_root_dir", "path/to/notebook.ipynb", "path/to/notebook.ipynb"), - ], -) -def test_resolve_file_to_run_and_root_dir(prefix_path, root_dir, file_to_run, expected_output): - # Verify that the Singleton instance is cleared before the test runs. - ServerApp.clear_instance() - - # Setup the file_to_run path, in case the server checks - # if the directory exists before initializing the server. - file_to_run = prefix_path(file_to_run) - if file_to_run.is_absolute(): - file_to_run.parent.mkdir(parents=True, exist_ok=True) - kwargs = {"file_to_run": str(file_to_run)} - - # Setup the root_dir path, in case the server checks - # if the directory exists before initializing the server. - if root_dir: - root_dir = prefix_path(root_dir) - if root_dir.is_absolute(): - root_dir.parent.mkdir(parents=True, exist_ok=True) - kwargs["root_dir"] = str(root_dir) - - # Create the notebook in the given location - serverapp = ServerApp.instance(**kwargs) - - if expected_output is SystemExit: - with pytest.raises(SystemExit): - serverapp._resolve_file_to_run_and_root_dir() - else: - relpath = serverapp._resolve_file_to_run_and_root_dir() - assert relpath == str(pathlib.Path(expected_output)) - - # Clear the singleton instance after each run. - ServerApp.clear_instance() - - -# Test the URLs returned by ServerApp. The `` piece -# in urls shown below will be replaced with the token -# generated by the ServerApp on instance creation. -@pytest.mark.parametrize( - "config,public_url,local_url,connection_url", - [ - # Token is hidden when configured. - ( - {"token": "test"}, - "http://localhost:8888/?token=...", - "http://127.0.0.1:8888/?token=...", - "http://localhost:8888/", - ), - # Verify port number has changed - ( - {"port": 9999}, - "http://localhost:9999/?token=%3Cgenerated%3E", - "http://127.0.0.1:9999/?token=%3Cgenerated%3E", - "http://localhost:9999/", - ), - ( - {"ip": "1.1.1.1"}, - "http://1.1.1.1:8888/?token=%3Cgenerated%3E", - "http://127.0.0.1:8888/?token=%3Cgenerated%3E", - "http://1.1.1.1:8888/", - ), - # Verify that HTTPS is returned when certfile is given - ( - {"certfile": "/path/to/dummy/file"}, - "https://localhost:8888/?token=%3Cgenerated%3E", - "https://127.0.0.1:8888/?token=%3Cgenerated%3E", - "https://localhost:8888/", - ), - # Verify changed port and a custom display URL - ( - {"port": 9999, "custom_display_url": "http://test.org/"}, - "http://test.org/?token=%3Cgenerated%3E", - "http://127.0.0.1:9999/?token=%3Cgenerated%3E", - "http://localhost:9999/", - ), - ( - {"base_url": "/", "default_url": "/test/"}, - "http://localhost:8888/test/?token=%3Cgenerated%3E", - "http://127.0.0.1:8888/test/?token=%3Cgenerated%3E", - "http://localhost:8888/", - ), - # Verify unix socket URLs are handled properly - ( - {"sock": "/tmp/jp-test.sock"}, - "http+unix://%2Ftmp%2Fjp-test.sock/?token=", - "http+unix://%2Ftmp%2Fjp-test.sock/?token=", - "http+unix://%2Ftmp%2Fjp-test.sock/", - ), - ( - {"base_url": "/", "default_url": "/test/", "sock": "/tmp/jp-test.sock"}, - "http+unix://%2Ftmp%2Fjp-test.sock/test/?token=", - "http+unix://%2Ftmp%2Fjp-test.sock/test/?token=", - "http+unix://%2Ftmp%2Fjp-test.sock/", - ), - ], -) -def test_urls(config, public_url, local_url, connection_url): - # Verify we're working with a clean instance. - ServerApp.clear_instance() - serverapp = ServerApp.instance(**config) - # If a token is generated (not set by config), update - # expected_url with token. - if serverapp._token_generated: - public_url = public_url.replace("", serverapp.token) - local_url = local_url.replace("", serverapp.token) - connection_url = connection_url.replace("", serverapp.token) - assert serverapp.public_url == public_url - assert serverapp.local_url == local_url - assert serverapp.connection_url == connection_url - # Cleanup singleton after test. - ServerApp.clear_instance() - - -# Preferred dir tests -# ---------------------------------------------------------------------------- -def test_valid_preferred_dir(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path) - assert app.root_dir == path - assert app.preferred_dir == path - assert app.root_dir == app.preferred_dir - - -def test_valid_preferred_dir_is_root_subdir(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - path_subdir = str(tmp_path / "subdir") - os.makedirs(path_subdir, exist_ok=True) - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path_subdir) - assert app.root_dir == path - assert app.preferred_dir == path_subdir - assert app.preferred_dir.startswith(app.root_dir) - - -def test_valid_preferred_dir_does_not_exist(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - path_subdir = str(tmp_path / "subdir") - with pytest.raises(TraitError) as error: - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path_subdir) - - assert "No such preferred dir:" in str(error) - - -def test_invalid_preferred_dir_does_not_exist(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - path_subdir = str(tmp_path / "subdir") - with pytest.raises(TraitError) as error: - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path_subdir) - - assert "No such preferred dir:" in str(error) - - -def test_invalid_preferred_dir_does_not_exist_set(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - path_subdir = str(tmp_path / "subdir") - - app = jp_configurable_serverapp(root_dir=path) - with pytest.raises(TraitError) as error: - app.preferred_dir = path_subdir - - assert "No such preferred dir:" in str(error) - - -def test_invalid_preferred_dir_not_root_subdir(tmp_path, jp_configurable_serverapp): - path = str(tmp_path / "subdir") - os.makedirs(path, exist_ok=True) - not_subdir_path = str(tmp_path) - - with pytest.raises(TraitError) as error: - app = jp_configurable_serverapp(root_dir=path, preferred_dir=not_subdir_path) - - assert "preferred_dir must be equal or a subdir of root_dir:" in str(error) - - -def test_invalid_preferred_dir_not_root_subdir_set(tmp_path, jp_configurable_serverapp): - path = str(tmp_path / "subdir") - os.makedirs(path, exist_ok=True) - not_subdir_path = str(tmp_path) - - app = jp_configurable_serverapp(root_dir=path) - with pytest.raises(TraitError) as error: - app.preferred_dir = not_subdir_path - - assert "preferred_dir must be equal or a subdir of root_dir:" in str(error) - - -def test_observed_root_dir_updates_preferred_dir(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - new_path = str(tmp_path / "subdir") - os.makedirs(new_path, exist_ok=True) - - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path) - app.root_dir = new_path - assert app.preferred_dir == new_path - - -def test_observed_root_dir_does_not_update_preferred_dir(tmp_path, jp_configurable_serverapp): - path = str(tmp_path) - new_path = str(tmp_path.parent) - app = jp_configurable_serverapp(root_dir=path, preferred_dir=path) - app.root_dir = new_path - assert app.preferred_dir == path diff --git a/server/jupyter_server/tests/test_terminal.py b/server/jupyter_server/tests/test_terminal.py deleted file mode 100644 index b9754e1..0000000 --- a/server/jupyter_server/tests/test_terminal.py +++ /dev/null @@ -1,179 +0,0 @@ -import asyncio -import json -import os -import shutil - -import pytest -from tornado.httpclient import HTTPClientError -from traitlets.config import Config - - -@pytest.fixture -def terminal_path(tmp_path): - subdir = tmp_path.joinpath("terminal_path") - subdir.mkdir() - - yield subdir - - shutil.rmtree(str(subdir), ignore_errors=True) - - -CULL_TIMEOUT = 10 -CULL_INTERVAL = 3 - - -@pytest.fixture -def jp_server_config(): - return Config( - { - "ServerApp": { - "TerminalManager": { - "cull_inactive_timeout": CULL_TIMEOUT, - "cull_interval": CULL_INTERVAL, - } - } - } - ) - - -async def test_no_terminals(jp_fetch): - resp_list = await jp_fetch( - "api", - "terminals", - method="GET", - allow_nonstandard_methods=True, - ) - - data = json.loads(resp_list.body.decode()) - - assert len(data) == 0 - - -async def test_terminal_create(jp_fetch, jp_cleanup_subprocesses): - resp = await jp_fetch( - "api", - "terminals", - method="POST", - allow_nonstandard_methods=True, - ) - term = json.loads(resp.body.decode()) - assert term["name"] == "1" - - resp_list = await jp_fetch( - "api", - "terminals", - method="GET", - allow_nonstandard_methods=True, - ) - - data = json.loads(resp_list.body.decode()) - - assert len(data) == 1 - assert data[0] == term - await jp_cleanup_subprocesses() - - -async def test_terminal_create_with_kwargs( - jp_fetch, jp_ws_fetch, terminal_path, jp_cleanup_subprocesses -): - resp_create = await jp_fetch( - "api", - "terminals", - method="POST", - body=json.dumps({"cwd": str(terminal_path)}), - allow_nonstandard_methods=True, - ) - - data = json.loads(resp_create.body.decode()) - term_name = data["name"] - - resp_get = await jp_fetch( - "api", - "terminals", - term_name, - method="GET", - allow_nonstandard_methods=True, - ) - - data = json.loads(resp_get.body.decode()) - - assert data["name"] == term_name - await jp_cleanup_subprocesses() - - -async def test_terminal_create_with_cwd( - jp_fetch, jp_ws_fetch, terminal_path, jp_cleanup_subprocesses -): - resp = await jp_fetch( - "api", - "terminals", - method="POST", - body=json.dumps({"cwd": str(terminal_path)}), - allow_nonstandard_methods=True, - ) - - data = json.loads(resp.body.decode()) - term_name = data["name"] - - ws = await jp_ws_fetch("https://github.com/terminals", "websocket", term_name) - - ws.write_message(json.dumps(["stdin", "pwd\r\n"])) - - message_stdout = "" - while True: - try: - message = await asyncio.wait_for(ws.read_message(), timeout=5.0) - except asyncio.TimeoutError: - break - - message = json.loads(message) - - if message[0] == "stdout": - message_stdout += message[1] - - ws.close() - - assert os.path.basename(terminal_path) in message_stdout - await jp_cleanup_subprocesses() - - -async def test_culling_config(jp_server_config, jp_configurable_serverapp): - terminal_mgr_config = jp_configurable_serverapp().config.ServerApp.TerminalManager - assert terminal_mgr_config.cull_inactive_timeout == CULL_TIMEOUT - assert terminal_mgr_config.cull_interval == CULL_INTERVAL - terminal_mgr_settings = jp_configurable_serverapp().web_app.settings["terminal_manager"] - assert terminal_mgr_settings.cull_inactive_timeout == CULL_TIMEOUT - assert terminal_mgr_settings.cull_interval == CULL_INTERVAL - - -async def test_culling(jp_server_config, jp_fetch, jp_cleanup_subprocesses): - # POST request - resp = await jp_fetch( - "api", - "terminals", - method="POST", - allow_nonstandard_methods=True, - ) - term = json.loads(resp.body.decode()) - term_1 = term["name"] - last_activity = term["last_activity"] - - culled = False - for i in range(CULL_TIMEOUT + CULL_INTERVAL): - try: - resp = await jp_fetch( - "api", - "terminals", - term_1, - method="GET", - allow_nonstandard_methods=True, - ) - except HTTPClientError as e: - assert e.code == 404 - culled = True - break - else: - await asyncio.sleep(1) - - assert culled - await jp_cleanup_subprocesses() diff --git a/server/jupyter_server/tests/test_traittypes.py b/server/jupyter_server/tests/test_traittypes.py deleted file mode 100644 index 0b1849f..0000000 --- a/server/jupyter_server/tests/test_traittypes.py +++ /dev/null @@ -1,72 +0,0 @@ -import pytest -from traitlets import HasTraits -from traitlets import TraitError -from traitlets.utils.importstring import import_item - -from jupyter_server.services.contents.largefilemanager import LargeFileManager -from jupyter_server.traittypes import InstanceFromClasses -from jupyter_server.traittypes import TypeFromClasses - - -class DummyClass: - """Dummy class for testing Instance""" - - -class DummyInt(int): - """Dummy class for testing types.""" - - -class Thing(HasTraits): - - a = InstanceFromClasses( - default_value=2, - klasses=[ - int, - str, - DummyClass, - ], - ) - - b = TypeFromClasses( - default_value=None, - allow_none=True, - klasses=[ - DummyClass, - int, - "jupyter_server.services.contents.manager.ContentsManager", - ], - ) - - -class TestInstanceFromClasses: - @pytest.mark.parametrize("value", [1, "test", DummyClass()]) - def test_good_values(self, value): - thing = Thing(a=value) - assert thing.a == value - - @pytest.mark.parametrize("value", [2.4, object()]) - def test_bad_values(self, value): - with pytest.raises(TraitError) as e: - thing = Thing(a=value) - - -class TestTypeFromClasses: - @pytest.mark.parametrize( - "value", - [ - DummyClass, - DummyInt, - LargeFileManager, - "jupyter_server.services.contents.manager.ContentsManager", - ], - ) - def test_good_values(self, value): - thing = Thing(b=value) - if isinstance(value, str): - value = import_item(value) - assert thing.b == value - - @pytest.mark.parametrize("value", [float, object]) - def test_bad_values(self, value): - with pytest.raises(TraitError) as e: - thing = Thing(b=value) diff --git a/server/jupyter_server/tests/test_utils.py b/server/jupyter_server/tests/test_utils.py deleted file mode 100644 index c49be09..0000000 --- a/server/jupyter_server/tests/test_utils.py +++ /dev/null @@ -1,63 +0,0 @@ -from pathlib import Path -from unittest.mock import patch - -import pytest -from traitlets.tests.utils import check_help_all_output - -from jupyter_server.utils import is_namespace_package -from jupyter_server.utils import url_escape -from jupyter_server.utils import url_unescape - - -def test_help_output(): - check_help_all_output("jupyter_server") - - -@pytest.mark.parametrize( - "unescaped,escaped", - [ - ("/this is a test/for spaces/", "/this%20is%20a%20test/for%20spaces/"), - ("notebook with space.ipynb", "notebook%20with%20space.ipynb"), - ( - "/path with a/notebook and space.ipynb", - "/path%20with%20a/notebook%20and%20space.ipynb", - ), - ( - "/ !@$#%^&* / test %^ notebook @#$ name.ipynb", - "/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb", - ), - ], -) -def test_url_escaping(unescaped, escaped): - # Test escaping. - path = url_escape(unescaped) - assert path == escaped - # Test unescaping. - path = url_unescape(escaped) - assert path == unescaped - - -@pytest.mark.parametrize( - "name, expected", - [ - # returns True if it is a namespace package - ("test_namespace", True), - # returns False if it isn't a namespace package - ("sys", False), - ("jupyter_server", False), - # returns None if it isn't importable - ("not_a_python_namespace", None), - ], -) -def test_is_namespace_package(monkeypatch, name, expected): - monkeypatch.syspath_prepend(Path(__file__).parent / "namespace-package-test") - - assert is_namespace_package(name) is expected - - -def test_is_namespace_package_no_spec(): - with patch("importlib.util.find_spec") as mocked_spec: - mocked_spec.side_effect = ValueError() - - assert is_namespace_package("dummy") is None - mocked_spec.assert_called_once_with("dummy") diff --git a/server/jupyter_server/tests/test_version.py b/server/jupyter_server/tests/test_version.py deleted file mode 100644 index 879c257..0000000 --- a/server/jupyter_server/tests/test_version.py +++ /dev/null @@ -1,51 +0,0 @@ -import re - -import pytest - -from jupyter_server import __version__ - - -pep440re = re.compile(r"^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$") - - -def raise_on_bad_version(version): - if not pep440re.match(version): - raise ValueError( - "Versions String does apparently not match Pep 440 specification, " - "which might lead to sdist and wheel being seen as 2 different release. " - "E.g: do not use dots for beta/alpha/rc markers." - ) - - -# --------- Meta test to test the versioning tests ------------- - - -@pytest.mark.parametrize( - "version", - [ - "4.1.0.b1", - "4.1.b1", - "4.2", - "X.y.z", - "1.2.3.dev1.post2", - ], -) -def test_invalid_pep440_versions(version): - with pytest.raises(ValueError): - raise_on_bad_version(version) - - -@pytest.mark.parametrize( - "version", - [ - "4.1.1", - "4.2.1b3", - ], -) -def test_valid_pep440_versions(version): - assert raise_on_bad_version(version) is None - - -# --------- Test current version -------------- -def test_current_version(): - raise_on_bad_version(__version__) diff --git a/server/jupyter_server/tests/test_view.py b/server/jupyter_server/tests/test_view.py deleted file mode 100644 index f6fbca5..0000000 --- a/server/jupyter_server/tests/test_view.py +++ /dev/null @@ -1,60 +0,0 @@ -"""test view handler""" -from html.parser import HTMLParser - -import pytest -import tornado - -from .utils import expected_http_error -from jupyter_server.utils import url_path_join - - -class IFrameSrcFinder(HTMLParser): - """Minimal HTML parser to find iframe.src attr""" - - def __init__(self): - super().__init__() - self.iframe_src = None - - def handle_starttag(self, tag, attrs): - if tag.lower() == "iframe": - for attr, value in attrs: - if attr.lower() == "src": - self.iframe_src = value - return - - -def find_iframe_src(html): - """Find the src= attr of an iframe on the page - - Assumes only one iframe - """ - finder = IFrameSrcFinder() - finder.feed(html) - return finder.iframe_src - - -@pytest.mark.parametrize( - "exists, name", - [ - (False, "nosuchfile.html"), - (False, "nosuchfile.bin"), - (True, "exists.html"), - (True, "exists.bin"), - ], -) -async def test_view(jp_fetch, jp_serverapp, jp_root_dir, exists, name): - """Test /view/$path for a few cases""" - if exists: - jp_root_dir.joinpath(name).write_text(name) - - if not exists: - with pytest.raises(tornado.httpclient.HTTPClientError) as e: - await jp_fetch("https://github.com/view", name, method="GET") - assert expected_http_error(e, 404), [name, e] - else: - r = await jp_fetch("https://github.com/view", name, method="GET") - assert r.code == 200 - assert r.headers["content-type"] == "text/html; charset=UTF-8" - html = r.body.decode() - src = find_iframe_src(html) - assert src == url_path_join(jp_serverapp.base_url, f"/files/{name}") diff --git a/server/jupyter_server/tests/unix_sockets/__init__.py b/server/jupyter_server/tests/unix_sockets/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/tests/unix_sockets/conftest.py b/server/jupyter_server/tests/unix_sockets/conftest.py deleted file mode 100644 index dffd4bb..0000000 --- a/server/jupyter_server/tests/unix_sockets/conftest.py +++ /dev/null @@ -1,34 +0,0 @@ -import os -import pathlib - -import pytest - -from jupyter_server import DEFAULT_JUPYTER_SERVER_PORT - - -@pytest.fixture -def jp_process_id(): - """Choose a random unused process ID.""" - return os.getpid() - - -@pytest.fixture -def jp_unix_socket_file(jp_process_id): - """Define a temporary socket connection""" - # Rely on `/tmp` to avoid any Linux socket length max buffer - # issues. Key on PID for process-wise concurrency. - tmp_path = pathlib.Path("/tmp") - filename = "jupyter_server.{}.sock".format(jp_process_id) - jp_unix_socket_file = tmp_path.joinpath(filename) - yield str(jp_unix_socket_file) - # Clean up the file after the test runs. - if jp_unix_socket_file.exists(): - jp_unix_socket_file.unlink() - - -@pytest.fixture -def jp_http_port(): - """Set the port to the default value, since sock - and port cannot both be configured at the same time. - """ - return DEFAULT_JUPYTER_SERVER_PORT diff --git a/server/jupyter_server/tests/unix_sockets/test_api.py b/server/jupyter_server/tests/unix_sockets/test_api.py deleted file mode 100644 index 1653a90..0000000 --- a/server/jupyter_server/tests/unix_sockets/test_api.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys - -import pytest - -# Skip this module if on Windows. Unix sockets are not available on Windows. -pytestmark = pytest.mark.skipif( - sys.platform.startswith("win"), reason="Unix sockets are not available on Windows." -) - -import urllib - -if not sys.platform.startswith("win"): - from tornado.netutil import bind_unix_socket - -import jupyter_server.serverapp -from jupyter_server.utils import ( - url_path_join, - urlencode_unix_socket, - async_fetch, -) - - -@pytest.fixture -def jp_server_config(jp_unix_socket_file): - """Configure the serverapp fixture with the unix socket.""" - return {"ServerApp": {"sock": jp_unix_socket_file, "allow_remote_access": True}} - - -@pytest.fixture -def http_server_port(jp_unix_socket_file, jp_process_id): - """Unix socket and process ID used by tornado's HTTP Server. - - Overrides the http_server_port fixture from pytest-tornasync and replaces - it with a tuple: (unix socket, process id) - """ - return (bind_unix_socket(jp_unix_socket_file), jp_process_id) - - -@pytest.fixture -def jp_unix_socket_fetch(jp_unix_socket_file, jp_auth_header, jp_base_url, http_server, io_loop): - """A fetch fixture for Jupyter Server tests that use the unix_serverapp fixture""" - - async def client(*parts, headers={}, params={}, **kwargs): - # Handle URL strings - host_url = urlencode_unix_socket(jp_unix_socket_file) - path_url = url_path_join(jp_base_url, *parts) - params_url = urllib.parse.urlencode(params) - url = url_path_join(host_url, path_url + "?" + params_url) - r = await async_fetch(url, headers=headers, io_loop=io_loop, **kwargs) - return r - - return client - - -async def test_get_spec(jp_unix_socket_fetch): - # Handle URL strings - parts = ["api", "spec.yaml"] - - # Make request and verify it succeeds.' - response = await jp_unix_socket_fetch(*parts) - assert response.code == 200 - assert response.body != None - - -async def test_list_running_servers(jp_unix_socket_file, http_server): - """Test that a server running on unix sockets is discovered by the server list""" - servers = list(jupyter_server.serverapp.list_running_servers()) - assert len(servers) >= 1 - assert jp_unix_socket_file in {info["sock"] for info in servers} diff --git a/server/jupyter_server/tests/unix_sockets/test_serverapp_integration.py b/server/jupyter_server/tests/unix_sockets/test_serverapp_integration.py deleted file mode 100644 index 69be15b..0000000 --- a/server/jupyter_server/tests/unix_sockets/test_serverapp_integration.py +++ /dev/null @@ -1,165 +0,0 @@ -import stat -import sys - -import pytest - -# Skip this module if on Windows. Unix sockets are not available on Windows. -pytestmark = pytest.mark.skipif( - sys.platform.startswith("win"), reason="Unix sockets are not available on Windows." -) - -import os -import subprocess -import time - -from jupyter_server.utils import urlencode_unix_socket, urlencode_unix_socket_path - - -@pytest.mark.integration_test -def test_shutdown_sock_server_integration(jp_unix_socket_file): - url = urlencode_unix_socket(jp_unix_socket_file).encode() - encoded_sock_path = urlencode_unix_socket_path(jp_unix_socket_file) - p = subprocess.Popen( - ["jupyter-server", "--sock=%s" % jp_unix_socket_file, "--sock-mode=0700"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - - complete = False - for line in iter(p.stderr.readline, b""): - if url in line: - complete = True - break - - assert complete, "did not find socket URL in stdout when launching notebook" - - socket_path = encoded_sock_path.encode() - assert socket_path in subprocess.check_output(["jupyter-server", "list"]) - - # Ensure umask is properly applied. - assert stat.S_IMODE(os.lstat(jp_unix_socket_file).st_mode) == 0o700 - - try: - subprocess.check_output(["jupyter-server", "stop"], stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - assert "There is currently no server running on" in e.output.decode() - else: - raise AssertionError("expected stop command to fail due to target mis-match") - - assert encoded_sock_path.encode() in subprocess.check_output(["jupyter-server", "list"]) - - subprocess.check_output(["jupyter-server", "stop", jp_unix_socket_file]) - - assert encoded_sock_path.encode() not in subprocess.check_output(["jupyter-server", "list"]) - - p.wait() - - -@pytest.mark.integration_test -def test_sock_server_validate_sockmode_type(): - try: - subprocess.check_output( - ["jupyter-server", "--sock=/tmp/nonexistent", "--sock-mode=badbadbad"], - stderr=subprocess.STDOUT, - ) - except subprocess.CalledProcessError as e: - assert "badbadbad" in e.output.decode() - else: - raise AssertionError("expected execution to fail due to validation of --sock-mode param") - - -@pytest.mark.integration_test -def test_sock_server_validate_sockmode_accessible(): - try: - subprocess.check_output( - ["jupyter-server", "--sock=/tmp/nonexistent", "--sock-mode=0444"], - stderr=subprocess.STDOUT, - ) - except subprocess.CalledProcessError as e: - assert "0444" in e.output.decode() - else: - raise AssertionError("expected execution to fail due to validation of --sock-mode param") - - -def _ensure_stopped(check_msg="There are no running servers"): - try: - subprocess.check_output(["jupyter-server", "stop"], stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - assert check_msg in e.output.decode() - else: - raise AssertionError("expected all servers to be stopped") - - -@pytest.mark.integration_test -def test_stop_multi_integration(jp_unix_socket_file, jp_http_port): - """Tests lifecycle behavior for mixed-mode server types w/ default ports. - - Mostly suitable for local dev testing due to reliance on default port binding. - """ - TEST_PORT = "9797" - MSG_TMPL = "Shutting down server on {}..." - - _ensure_stopped() - - # Default port. - p1 = subprocess.Popen(["jupyter-server", "--no-browser"]) - - # Unix socket. - p2 = subprocess.Popen(["jupyter-server", "--sock=%s" % jp_unix_socket_file]) - - # Specified port - p3 = subprocess.Popen(["jupyter-server", "--no-browser", "--port=%s" % TEST_PORT]) - - time.sleep(3) - - shutdown_msg = MSG_TMPL.format(jp_http_port) - assert shutdown_msg in subprocess.check_output(["jupyter-server", "stop"]).decode() - - _ensure_stopped("There is currently no server running on 8888") - - assert ( - MSG_TMPL.format(jp_unix_socket_file) - in subprocess.check_output(["jupyter-server", "stop", jp_unix_socket_file]).decode() - ) - - assert ( - MSG_TMPL.format(TEST_PORT) - in subprocess.check_output(["jupyter-server", "stop", TEST_PORT]).decode() - ) - - _ensure_stopped() - - p1.wait() - p2.wait() - p3.wait() - - -@pytest.mark.integration_test -def test_launch_socket_collision(jp_unix_socket_file): - """Tests UNIX socket in-use detection for lifecycle correctness.""" - sock = jp_unix_socket_file - check_msg = "socket %s is already in use" % sock - - _ensure_stopped() - - # Start a server. - cmd = ["jupyter-server", "--sock=%s" % sock] - p1 = subprocess.Popen(cmd) - time.sleep(3) - - # Try to start a server bound to the same UNIX socket. - try: - subprocess.check_output(cmd, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as cpe: - assert check_msg in cpe.output.decode() - except Exception as ex: - raise AssertionError(f"expected 'already in use' error, got '{ex}'!") - else: - raise AssertionError("expected 'already in use' error, got success instead!") - - # Stop the background server, ensure it's stopped and wait on the process to exit. - subprocess.check_call(["jupyter-server", "stop", sock]) - - _ensure_stopped() - - p1.wait() diff --git a/server/jupyter_server/tests/utils.py b/server/jupyter_server/tests/utils.py deleted file mode 100644 index 6e6649a..0000000 --- a/server/jupyter_server/tests/utils.py +++ /dev/null @@ -1,41 +0,0 @@ -import json - -import tornado - -some_resource = "The very model of a modern major general" - -sample_kernel_json = { - "argv": ["cat", "{connection_file}"], - "display_name": "Test kernel", -} - - -def mkdir(tmp_path, *parts): - path = tmp_path.joinpath(*parts) - if not path.exists(): - path.mkdir(parents=True) - return path - - -def expected_http_error(error, expected_code, expected_message=None): - """Check that the error matches the expected output error.""" - e = error.value - if isinstance(e, tornado.web.HTTPError): - if expected_code != e.status_code: - return False - if expected_message is not None and expected_message != str(e): - return False - return True - elif any( - [ - isinstance(e, tornado.httpclient.HTTPClientError), - isinstance(e, tornado.httpclient.HTTPError), - ] - ): - if expected_code != e.code: - return False - if expected_message: - message = json.loads(e.response.body.decode())["message"] - if expected_message != message: - return False - return True diff --git a/server/jupyter_server/traittypes.py b/server/jupyter_server/traittypes.py deleted file mode 100644 index 5c6ede5..0000000 --- a/server/jupyter_server/traittypes.py +++ /dev/null @@ -1,224 +0,0 @@ -import inspect -from ast import literal_eval - -from traitlets import ClassBasedTraitType -from traitlets import TraitError -from traitlets import Undefined -from traitlets.utils.descriptions import describe - - -class TypeFromClasses(ClassBasedTraitType): - """A trait whose value must be a subclass of a class in a specified list of classes.""" - - def __init__(self, default_value=Undefined, klasses=None, **kwargs): - """Construct a Type trait - A Type trait specifies that its values must be subclasses of - a class in a list of possible classes. - If only ``default_value`` is given, it is used for the ``klasses`` as - well. If neither are given, both default to ``object``. - Parameters - ---------- - default_value : class, str or None - The default value must be a subclass of klass. If an str, - the str must be a fully specified class name, like 'foo.bar.Bah'. - The string is resolved into real class, when the parent - :class:`HasTraits` class is instantiated. - klasses : list of class, str [ default object ] - Values of this trait must be a subclass of klass. The klass - may be specified in a string like: 'foo.bar.MyClass'. - The string is resolved into real class, when the parent - :class:`HasTraits` class is instantiated. - allow_none : bool [ default False ] - Indicates whether None is allowed as an assignable value. - """ - if default_value is Undefined: - new_default_value = object if (klasses is None) else klasses - else: - new_default_value = default_value - - if klasses is None: - if (default_value is None) or (default_value is Undefined): - klasses = [object] - else: - klasses = [default_value] - - # OneOfType requires a list of klasses to be specified (different than Type). - if not isinstance(klasses, (list, tuple, set)): - raise TraitError("`klasses` must be a list of class names (type is str) or classes.") - - for klass in klasses: - if not (inspect.isclass(klass) or isinstance(klass, str)): - raise TraitError("A OneOfType trait must specify a list of classes.") - - # Store classes. - self.klasses = klasses - - super().__init__(new_default_value, **kwargs) - - def subclass_from_klasses(self, value): - "Check that a given class is a subclasses found in the klasses list." - return any(issubclass(value, klass) for klass in self.importable_klasses) - - def validate(self, obj, value): - """Validates that the value is a valid object instance.""" - if isinstance(value, str): - try: - value = self._resolve_string(value) - except ImportError: - raise TraitError( - "The '%s' trait of %s instance must be a type, but " - "%r could not be imported" % (self.name, obj, value) - ) - try: - if self.subclass_from_klasses(value): - return value - except Exception: - pass - - self.error(obj, value) - - def info(self): - """Returns a description of the trait.""" - result = "a subclass of " - for klass in self.klasses: - if not isinstance(klass, str): - klass = klass.__module__ + "." + klass.__name__ - result += f"{klass} or " - # Strip the last "or" - result = result.strip(" or ") - if self.allow_none: - return result + " or None" - return result - - def instance_init(self, obj): - self._resolve_classes() - super().instance_init(obj) - - def _resolve_classes(self): - # Resolve all string names to actual classes. - self.importable_klasses = [] - for klass in self.klasses: - if isinstance(klass, str): - # Try importing the classes to compare. Silently, ignore if not importable. - try: - klass = self._resolve_string(klass) - self.importable_klasses.append(klass) - except: - pass - else: - self.importable_klasses.append(klass) - - if isinstance(self.default_value, str): - self.default_value = self._resolve_string(self.default_value) - - def default_value_repr(self): - value = self.default_value - if isinstance(value, str): - return repr(value) - else: - return repr(f"{value.__module__}.{value.__name__}") - - -class InstanceFromClasses(ClassBasedTraitType): - """A trait whose value must be an instance of a class in a specified list of classes. - The value can also be an instance of a subclass of the specified classes. - Subclasses can declare default classes by overriding the klass attribute - """ - - def __init__(self, klasses=None, args=None, kw=None, **kwargs): - """Construct an Instance trait. - This trait allows values that are instances of a particular - class or its subclasses. Our implementation is quite different - from that of enthough.traits as we don't allow instances to be used - for klass and we handle the ``args`` and ``kw`` arguments differently. - Parameters - ---------- - klasses : list of classes or class_names (str) - The class that forms the basis for the trait. Class names - can also be specified as strings, like 'foo.bar.Bar'. - args : tuple - Positional arguments for generating the default value. - kw : dict - Keyword arguments for generating the default value. - allow_none : bool [ default False ] - Indicates whether None is allowed as a value. - Notes - ----- - If both ``args`` and ``kw`` are None, then the default value is None. - If ``args`` is a tuple and ``kw`` is a dict, then the default is - created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is - None, the None is replaced by ``()`` or ``{}``, respectively. - """ - # If class - if klasses is None: - self.klasses = klasses - # Verify all elements are either classes or strings. - elif all(inspect.isclass(k) or isinstance(k, str) for k in klasses): - self.klasses = klasses - else: - raise TraitError( - "The klasses attribute must be a list of class names or classes" - " not: %r" % klasses - ) - - if (kw is not None) and not isinstance(kw, dict): - raise TraitError("The 'kw' argument must be a dict or None.") - if (args is not None) and not isinstance(args, tuple): - raise TraitError("The 'args' argument must be a tuple or None.") - - self.default_args = args - self.default_kwargs = kw - - super(InstanceFromClasses, self).__init__(**kwargs) - - def instance_from_importable_klasses(self, value): - "Check that a given class is a subclasses found in the klasses list." - return any(isinstance(value, klass) for klass in self.importable_klasses) - - def validate(self, obj, value): - if self.instance_from_importable_klasses(value): - return value - else: - self.error(obj, value) - - def info(self): - result = "an instance of " - for klass in self.klasses: - if isinstance(klass, str): - result += klass - else: - result += describe("a", klass) - result += " or " - result = result.strip(" or ") - if self.allow_none: - result += " or None" - return result - - def instance_init(self, obj): - self._resolve_classes() - super().instance_init(obj) - - def _resolve_classes(self): - # Resolve all string names to actual classes. - self.importable_klasses = [] - for klass in self.klasses: - if isinstance(klass, str): - # Try importing the classes to compare. Silently, ignore if not importable. - try: - klass = self._resolve_string(klass) - self.importable_klasses.append(klass) - except: - pass - else: - self.importable_klasses.append(klass) - - def make_dynamic_default(self): - if (self.default_args is None) and (self.default_kwargs is None): - return None - return self.klass(*(self.default_args or ()), **(self.default_kwargs or {})) - - def default_value_repr(self): - return repr(self.make_dynamic_default()) - - def from_string(self, s): - return literal_eval(s) diff --git a/server/jupyter_server/transutils.py b/server/jupyter_server/transutils.py deleted file mode 100644 index 2ca30e4..0000000 --- a/server/jupyter_server/transutils.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Translation related utilities. When imported, injects _ to builtins""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import gettext -import os -import warnings - - -def _trans_gettext_deprecation_helper(*args, **kwargs): - warn_msg = "The alias `_()` will be deprecated. Use `_i18n()` instead." - warnings.warn(warn_msg, FutureWarning, stacklevel=2) - return trans.gettext(*args, **kwargs) - - -# Set up message catalog access -base_dir = os.path.realpath(os.path.join(__file__, "..", "..")) -trans = gettext.translation( - "notebook", localedir=os.path.join(base_dir, "notebook/i18n"), fallback=True -) -_ = _trans_gettext_deprecation_helper -_i18n = trans.gettext diff --git a/server/jupyter_server/utils.py b/server/jupyter_server/utils.py deleted file mode 100644 index 74239c0..0000000 --- a/server/jupyter_server/utils.py +++ /dev/null @@ -1,387 +0,0 @@ -"""Notebook related utilities""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import asyncio -import errno -import importlib.util -import inspect -import os -import socket -import sys -from _frozen_importlib_external import _NamespacePath -from contextlib import contextmanager -from urllib.parse import quote -from urllib.parse import SplitResult -from urllib.parse import unquote -from urllib.parse import urljoin # noqa: F401 -from urllib.parse import urlparse -from urllib.parse import urlsplit -from urllib.parse import urlunsplit -from urllib.request import pathname2url # noqa: F401 - -from packaging.version import Version -from tornado.httpclient import AsyncHTTPClient -from tornado.httpclient import HTTPClient -from tornado.httpclient import HTTPRequest -from tornado.netutil import Resolver - - -def url_path_join(*pieces): - """Join components of url into a relative url - - Use to prevent double slash when joining subpath. This will leave the - initial and final / in place - """ - initial = pieces[0].startswith("/") - final = pieces[-1].endswith("/") - stripped = [s.strip("/") for s in pieces] - result = "/".join(s for s in stripped if s) - if initial: - result = "/" + result - if final: - result = result + "/" - if result == "//": - result = "/" - return result - - -def url_is_absolute(url): - """Determine whether a given URL is absolute""" - return urlparse(url).path.startswith("/") - - -def path2url(https://github.com/path): - """Convert a local file path to a URL""" - pieces = [quote(p) for p in path.split(os.sep)] - # preserve trailing / - if pieces[-1] == "": - pieces[-1] = "/" - url = url_path_join(*pieces) - return url - - -def url2path(url): - """Convert a URL to a local file path""" - pieces = [unquote(p) for p in url.split("/")] - path = os.path.join(*pieces) - return path - - -def url_escape(path): - """Escape special characters in a URL path - - Turns '/foo bar/' into '/foo%20bar/' - """ - parts = path.split("/") - return "/".join([quote(p) for p in parts]) - - -def url_unescape(path): - """Unescape special characters in a URL path - - Turns '/foo%20bar/' into '/foo bar/' - """ - return "/".join([unquote(p) for p in path.split("/")]) - - -def samefile_simple(path, other_path): - """ - Fill in for os.path.samefile when it is unavailable (Windows+py2). - - Do a case-insensitive string comparison in this case - plus comparing the full stat result (including times) - because Windows + py2 doesn't support the stat fields - needed for identifying if it's the same file (st_ino, st_dev). - - Only to be used if os.path.samefile is not available. - - Parameters - ---------- - path : String representing a path to a file - other_path : String representing a path to another file - - Returns - ------- - same: Boolean that is True if both path and other path are the same - """ - path_stat = os.stat(path) - other_path_stat = os.stat(other_path) - return path.lower() == other_path.lower() and path_stat == other_path_stat - - -def to_os_path(path, root=""): - """Convert an API path to a filesystem path - - If given, root will be prepended to the path. - root must be a filesystem path already. - """ - parts = path.strip("/").split("/") - parts = [p for p in parts if p != ""] # remove duplicate splits - path = os.path.join(root, *parts) - return path - - -def to_api_path(os_path, root=""): - """Convert a filesystem path to an API path - - If given, root will be removed from the path. - root must be a filesystem path already. - """ - if os_path.startswith(root): - os_path = os_path[len(root) :] - parts = os_path.strip(os.path.sep).split(os.path.sep) - parts = [p for p in parts if p != ""] # remove duplicate splits - path = "/".join(parts) - return path - - -def check_version(v, check): - """check version string v >= check - - If dev/prerelease tags result in TypeError for string-number comparison, - it is assumed that the dependency is satisfied. - Users on dev branches are responsible for keeping their own packages up to date. - """ - try: - return Version(v) >= Version(check) - except TypeError: - return True - - -# Copy of IPython.utils.process.check_pid: - - -def _check_pid_win32(pid): - import ctypes - - # OpenProcess returns 0 if no such process (of ours) exists - # positive int otherwise - return bool(ctypes.windll.kernel32.OpenProcess(1, 0, pid)) - - -def _check_pid_posix(pid): - """Copy of IPython.utils.process.check_pid""" - try: - os.kill(pid, 0) - except OSError as err: - if err.errno == errno.ESRCH: - return False - elif err.errno == errno.EPERM: - # Don't have permission to signal the process - probably means it exists - return True - raise - else: - return True - - -if sys.platform == "win32": - check_pid = _check_pid_win32 -else: - check_pid = _check_pid_posix - - -async def ensure_async(obj): - """Convert a non-awaitable object to a coroutine if needed, - and await it if it was not already awaited. - """ - if inspect.isawaitable(obj): - try: - result = await obj - except RuntimeError as e: - if str(e) == "cannot reuse already awaited coroutine": - # obj is already the coroutine's result - return obj - raise - return result - # obj doesn't need to be awaited - return obj - - -def run_sync(maybe_async): - """If async, runs maybe_async and blocks until it has executed, - possibly creating an event loop. - If not async, just returns maybe_async as it is the result of something - that has already executed. - - Parameters - ---------- - maybe_async : async or non-async object - The object to be executed, if it is async. - - Returns - ------- - result - Whatever the async object returns, or the object itself. - """ - if not inspect.isawaitable(maybe_async): - # that was not something async, just return it - return maybe_async - # it is async, we need to run it in an event loop - def wrapped(): - create_new_event_loop = False - try: - loop = asyncio.get_event_loop() - except RuntimeError: - create_new_event_loop = True - else: - if loop.is_closed(): - create_new_event_loop = True - if create_new_event_loop: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - result = loop.run_until_complete(maybe_async) - except RuntimeError as e: - if str(e) == "This event loop is already running": - # just return a Future, hoping that it will be awaited - result = asyncio.ensure_future(maybe_async) - else: - raise e - return result - - return wrapped() - - -async def run_sync_in_loop(maybe_async): - """Runs a function synchronously whether it is an async function or not. - - If async, runs maybe_async and blocks until it has executed. - - If not async, just returns maybe_async as it is the result of something - that has already executed. - - Parameters - ---------- - maybe_async : async or non-async object - The object to be executed, if it is async. - - Returns - ------- - result - Whatever the async object returns, or the object itself. - """ - if not inspect.isawaitable(maybe_async): - return maybe_async - return await maybe_async - - -def urlencode_unix_socket_path(socket_path): - """Encodes a UNIX socket path string from a socket path for the `http+unix` URI form.""" - return socket_path.replace("/", "%2F") - - -def urldecode_unix_socket_path(socket_path): - """Decodes a UNIX sock path string from an encoded sock path for the `http+unix` URI form.""" - return socket_path.replace("%2F", "/") - - -def urlencode_unix_socket(socket_path): - """Encodes a UNIX socket URL from a socket path for the `http+unix` URI form.""" - return "http+unix://%s" % urlencode_unix_socket_path(socket_path) - - -def unix_socket_in_use(socket_path): - """Checks whether a UNIX socket path on disk is in use by attempting to connect to it.""" - if not os.path.exists(socket_path): - return False - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(socket_path) - except socket.error: - return False - else: - return True - finally: - sock.close() - - -@contextmanager -def _request_for_tornado_client(urlstring, method="GET", body=None, headers=None): - """A utility that provides a context that handles - HTTP, HTTPS, and HTTP+UNIX request. - Creates a tornado HTTPRequest object with a URL - that tornado's HTTPClients can accept. - If the request is made to a unix socket, temporarily - configure the AsyncHTTPClient to resolve the URL - and connect to the proper socket. - """ - parts = urlsplit(urlstring) - if parts.scheme in ["http", "https"]: - pass - elif parts.scheme == "http+unix": - # If unix socket, mimic HTTP. - parts = SplitResult( - scheme="http", - netloc=parts.netloc, - path=parts.path, - query=parts.query, - fragment=parts.fragment, - ) - - class UnixSocketResolver(Resolver): - """A resolver that routes HTTP requests to unix sockets - in tornado HTTP clients. - Due to constraints in Tornados' API, the scheme of the - must be `http` (not `http+unix`). Applications should replace - the scheme in URLS before making a request to the HTTP client. - """ - - def initialize(self, resolver): - self.resolver = resolver - - def close(self): - self.resolver.close() - - async def resolve(self, host, port, *args, **kwargs): - return [(socket.AF_UNIX, urldecode_unix_socket_path(host))] - - resolver = UnixSocketResolver(resolver=Resolver()) - AsyncHTTPClient.configure(None, resolver=resolver) - else: - raise Exception("Unknown URL scheme.") - - # Yield the request for the given client. - url = urlunsplit(parts) - request = HTTPRequest(url, method=method, body=body, headers=headers) - yield request - - -def fetch(urlstring, method="GET", body=None, headers=None): - """ - Send a HTTP, HTTPS, or HTTP+UNIX request - to a Tornado Web Server. Returns a tornado HTTPResponse. - """ - with _request_for_tornado_client(urlstring) as request: - response = HTTPClient(AsyncHTTPClient).fetch(request) - return response - - -async def async_fetch(urlstring, method="GET", body=None, headers=None, io_loop=None): - """ - Send an asynchronous HTTP, HTTPS, or HTTP+UNIX request - to a Tornado Web Server. Returns a tornado HTTPResponse. - """ - with _request_for_tornado_client(urlstring) as request: - response = await AsyncHTTPClient(io_loop).fetch(request) - return response - - -def is_namespace_package(namespace): - """Is the provided namespace a Python Namespace Package (PEP420). - - https://www.python.org/dev/peps/pep-0420/#specification - - Returns `None` if module is not importable. - - """ - # NOTE: using submodule_search_locations because the loader can be None - try: - spec = importlib.util.find_spec(namespace) - except ValueError: # spec is not set - see https://docs.python.org/3/library/importlib.html#importlib.util.find_spec - return None - - if not spec: - # e.g. module not installed - return None - return isinstance(spec.submodule_search_locations, _NamespacePath) diff --git a/server/jupyter_server/view/__init__.py b/server/jupyter_server/view/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/jupyter_server/view/handlers.py b/server/jupyter_server/view/handlers.py deleted file mode 100644 index a7d50f2..0000000 --- a/server/jupyter_server/view/handlers.py +++ /dev/null @@ -1,37 +0,0 @@ -# encoding: utf-8 -"""Tornado handlers for viewing HTML files.""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -from tornado import web - -from ..base.handlers import JupyterHandler -from ..base.handlers import path_regex -from ..utils import ensure_async -from ..utils import url_escape -from ..utils import url_path_join -from jupyter_server.auth import authorized - - -AUTH_RESOURCE = "contents" - - -class ViewHandler(JupyterHandler): - """Render HTML files within an iframe.""" - - auth_resource = AUTH_RESOURCE - - @web.authenticated - @authorized - async def get(self, path): - path = path.strip("/") - if not await ensure_async(self.contents_manager.file_exists(path)): - raise web.HTTPError(404, "File does not exist: %s" % path) - - basename = path.rsplit("/", 1)[-1] - file_url = url_path_join(self.base_url, "files", url_escape(path)) - self.write(self.render_template("view.html", file_url=file_url, page_title=basename)) - - -default_handlers = [ - (r"/view%s" % path_regex, ViewHandler), -] diff --git a/server/package-lock.json b/server/package-lock.json deleted file mode 100644 index 3e30b1e..0000000 --- a/server/package-lock.json +++ /dev/null @@ -1,320 +0,0 @@ -{ - "name": "jupyter_server", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "bootstrap": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "requires": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "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-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - } - } -} diff --git a/server/package.json b/server/package.json deleted file mode 100644 index d4c9c73..0000000 --- a/server/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "jupyter_server", - "private": true, - "version": "1.0.0", - "license": "BSD", - "scripts": { - "build": "copyfiles -f node_modules/bootstrap/dist/css/*.min.* jupyter_server/static/style" - }, - "dependencies": { - "bootstrap": "^3.4.0", - "copyfiles": "^2.4.1" - } -} diff --git a/server/pyproject.toml b/server/pyproject.toml deleted file mode 100644 index 7e7bfa8..0000000 --- a/server/pyproject.toml +++ /dev/null @@ -1,43 +0,0 @@ -[build-system] -requires = ["jupyter_packaging~=0.9"] -build-backend = "jupyter_packaging.build_api" - -[tool.jupyter-packaging.builder] -factory = "jupyter_packaging.npm_builder" - -[tool.check-manifest] -ignore = ["tbump.toml", ".*", "*.yml", "package-lock.json", "bootstrap*", "conftest.py"] - -[tool.pytest.ini_options] -addopts = "--doctest-modules" -testpaths = [ - "jupyter_server/" -] -timeout = 300 -timeout_method = "thread" - -[tool.jupyter-releaser] -skip = ["check-links"] - -[tool.tbump.version] -current = "1.14.0.dev0" -regex = ''' - (?P\d+)\.(?P\d+)\.(?P\d+) - ((?Pa|b|rc|.dev)(?P\d+))? -''' - -[tool.tbump.git] -message_template = "Bump to {new_version}" -tag_template = "v{new_version}" - -[[tool.tbump.file]] -src = "jupyter_server/_version.py" -version_template = '({major}, {minor}, {patch}, "{channel}", "{release}")' - -[[tool.tbump.field]] -name = "channel" -default = "" - -[[tool.tbump.field]] -name = "release" -default = "" diff --git a/server/readthedocs.yml b/server/readthedocs.yml deleted file mode 100644 index 011118f..0000000 --- a/server/readthedocs.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 -sphinx: - configuration: docs/source/conf.py -conda: - environment: docs/environment.yml -python: - version: 3.8 - install: - # install itself with pip install . - - method: pip - path: . diff --git a/server/setup.cfg b/server/setup.cfg deleted file mode 100644 index 322c510..0000000 --- a/server/setup.cfg +++ /dev/null @@ -1,76 +0,0 @@ -[metadata] -name = jupyter_server -version = attr: jupyter_server.__version__ -description = The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications. -long_description = file: README.md -long_description_content_type = text/markdown -license_files = COPYING.md -author = Jupyter Development Team -author_email = jupyter@googlegroups.com -url = https://jupyter.org -platforms = Linux, Mac OS X, Windows -keywords = ipython, jupyter -classifiers = - 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 - -[options] -zip_safe = False -include_package_data = True -packages = find: -python_requires = >=3.7 -install_requires = - jinja2 - tornado>=6.1.0 - pyzmq>=17 - argon2-cffi - ipython_genutils - traitlets>=5 - jupyter_core>=4.6.0 - jupyter_client>=6.1.1 - nbformat - nbconvert - Send2Trash - terminado>=0.8.3 - prometheus_client - anyio>=3.1.0,<4 - websocket-client - packaging - pywinpty(<2);os_name=='nt' - -[options.extras_require] -test = - coverage - pytest>=6.0 - pytest-cov - pytest-mock - pytest-timeout - requests - pytest-tornasync - pytest-console-scripts - ipykernel - # NOTE: we cannot auto install examples/simple here because of: - # https://github.com/pypa/pip/issues/6658 - -[options.entry_points] -console_scripts = - jupyter-server = jupyter_server.serverapp:main - -[options.packages.find] -exclude = ['docs*', 'examples*'] - -[flake8] -ignore = E, C, W, F403, F811, F841, E402, I100, I101, D400 -builtins = c, get_config -exclude = - .cache, - .github, - docs, - setup.py diff --git a/server/setup.py b/server/setup.py deleted file mode 100644 index 9a33dcc..0000000 --- a/server/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -from setuptools import setup - -try: - from jupyter_packaging import wrap_installers, npm_builder - - ensured_targets = ["jupyter_server/static/style/bootstrap.min.css"] - cmdclass = wrap_installers(pre_develop=npm_builder(), ensured_targets=ensured_targets) -except ImportError: - cmdclass = {} - -setup(cmdclass=cmdclass) diff --git a/server/yarn.lock b/server/yarn.lock deleted file mode 100644 index 95bc2a3..0000000 --- a/server/yarn.lock +++ /dev/null @@ -1,295 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.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" - -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== - -bootstrap@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72" - integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA== - -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" - -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" - -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.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== - -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= - -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -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== - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -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= - -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== - -glob@^7.0.5: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - 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" - -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.1, 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== - -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== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -minimatch@^3.0.3, minimatch@^3.0.4: - 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" - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -noms@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" - integrity sha1-2o69nzr51nYJGbJ9nNyAkqczKFk= - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -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= - -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== - -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -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" - -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= - -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== - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -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.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -through2@^2.0.1: - 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" - -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - -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= - -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= - -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== - -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== - -yargs-parser@^20.2.2: - 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@^16.1.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" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8885a53..0000000 --- a/setup.cfg +++ /dev/null @@ -1,55 +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 - -[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.10 - jupyter_server~=1.4 - nbclassic~=0.2 - jinja2>=2.1 - -[options.extras_require] -test = coverage; pytest>=6.0; pytest-cov; pytest-console-scripts; pytest-check-links>=0.5; jupyterlab_server[test]~=2.2; requests; requests_cache; virtualenv; check-manifest -ui-tests = build - -[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 a247a0f..4abca77 100644 --- a/setup.py +++ b/setup.py @@ -1,64 +1,5 @@ -#!/usr/bin/env python -# coding: utf-8 - # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from os.path import join as pjoin -import json -import os -import os.path as osp -import sys - -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 packaging.version import Version - from jupyter_packaging import get_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 wrap_installers, npm_builder, get_data_files - - npm = ['node', pjoin(HERE, NAME, 'staging', 'yarn.js')] - # In develop mode, just run yarn - builder = npm_builder(build_cmd=None, npm=npm, force=True) - cmdclass = wrap_installers(post_develop=builder, 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 index 1b99525..120c4da 100644 --- a/testutils/babel.config.js +++ b/testutils/babel.config.js @@ -1 +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/testutils/jest.config.js b/testutils/jest.config.js index 7a7c726..ba98a0e 100644 --- a/testutils/jest.config.js +++ b/testutils/jest.config.js @@ -1,2 +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/testutils/package.json b/testutils/package.json index ae3e9aa..8e41e9d 100644 --- a/testutils/package.json +++ b/testutils/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/testutils", - "version": "3.3.2", + "version": "4.0.0-alpha.12", "description": "JupyterLab - Test Utilities", "homepage": "https://github.com/jupyterlab/jupyterlab", "bugs": { @@ -36,20 +36,20 @@ "watch": "tsc -b --watch" }, "dependencies": { - "@jupyterlab/apputils": "^3.3.2", - "@jupyterlab/cells": "^3.3.2", - "@jupyterlab/codeeditor": "^3.3.2", - "@jupyterlab/codemirror": "^3.3.2", - "@jupyterlab/coreutils": "^5.3.2", - "@jupyterlab/docregistry": "^3.3.2", - "@jupyterlab/nbformat": "^3.3.2", - "@jupyterlab/notebook": "^3.3.2", - "@jupyterlab/rendermime": "^3.3.2", - "@jupyterlab/services": "^6.3.2", - "@lumino/algorithm": "^1.3.3", - "@lumino/coreutils": "^1.5.3", - "@lumino/properties": "^1.2.3", - "@lumino/signaling": "^1.4.3", + "@jupyterlab/apputils": "^4.0.0-alpha.12", + "@jupyterlab/cells": "^4.0.0-alpha.12", + "@jupyterlab/codeeditor": "^4.0.0-alpha.12", + "@jupyterlab/codemirror": "^4.0.0-alpha.12", + "@jupyterlab/coreutils": "^6.0.0-alpha.12", + "@jupyterlab/docregistry": "^4.0.0-alpha.12", + "@jupyterlab/nbformat": "^4.0.0-alpha.12", + "@jupyterlab/notebook": "^4.0.0-alpha.12", + "@jupyterlab/rendermime": "^4.0.0-alpha.12", + "@jupyterlab/services": "^7.0.0-alpha.12", + "@lumino/algorithm": "^1.9.1", + "@lumino/coreutils": "^1.12.0", + "@lumino/properties": "^1.8.1", + "@lumino/signaling": "^1.10.1", "child_process": "~1.0.2", "deepmerge": "^4.2.2", "fs-extra": "^9.0.1", @@ -59,17 +59,16 @@ "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" }, "devDependencies": { "@types/jest": "^26.0.10", + "@types/node": "^14.6.1", "@types/node-fetch": "^2.5.4", "jest-retries": "^1.0.1", - "lighthouse": "6.3.0", - "typescript": "~4.1.3" + "typescript": "~4.7.3" }, "publishConfig": { "access": "public" diff --git a/testutils/src/babel.config.ts b/testutils/src/babel.config.ts index 6c3be4c..caf3177 100644 --- a/testutils/src/babel.config.ts +++ b/testutils/src/babel.config.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + module.exports = { presets: [ [ diff --git a/testutils/src/common.ts b/testutils/src/common.ts index 0d8825c..8cef6bb 100644 --- a/testutils/src/common.ts +++ b/testutils/src/common.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import { simulate } from 'simulate-event'; import { ServiceManager, Session } from '@jupyterlab/services'; @@ -183,6 +188,7 @@ export function sleep(milliseconds?: number): Promise; export function sleep(milliseconds: number, value: T): Promise; export function sleep( milliseconds: number = 0, + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types value?: any ): Promise | Promise { return new Promise((resolve, reject) => { @@ -241,7 +247,7 @@ export function createFileContext( export async function createFileContextWithKernel( path: string = UUID.uuid4() + '.txt', manager: ServiceManager.IManager = Private.getManager() -) { +): Promise { const factory = Private.textFactory; const specsManager = manager.kernelspecs; await specsManager.ready; diff --git a/testutils/src/compare-lighthouse.ts b/testutils/src/compare-lighthouse.ts deleted file mode 100644 index c4fb4e8..0000000 --- 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 index 9d85e27..c2c999f 100644 --- a/testutils/src/flakyIt.ts +++ b/testutils/src/flakyIt.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // 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 @@ -33,7 +38,9 @@ async function runTest(fn: any): Promise { * @param wait The time to wait in milliseconds between retries */ /* eslint-disable jest/no-export */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function flakyIt(name: string, fn: any, retries = 3, wait = 1000): void { + // eslint-disable-next-line jest/expect-expect, jest/valid-title test(name, async () => { let latestError; for (let tries = 0; tries < retries; tries++) { diff --git a/testutils/src/jest-config.ts b/testutils/src/jest-config.ts index 1bfcfe4..066b824 100644 --- a/testutils/src/jest-config.ts +++ b/testutils/src/jest-config.ts @@ -1,6 +1,18 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + import path from 'path'; -const esModules = ['lib0', 'y\\-protocols', 'y\\-websocket', 'yjs'].join('|'); +const esModules = [ + '@codemirror', + 'lib0', + 'vscode\\-ws\\-jsonrpc', + 'y\\-protocols', + 'y\\-websocket', + 'yjs' +].join('|'); module.exports = function (baseDir: string) { return { @@ -10,8 +22,7 @@ module.exports = function (baseDir: string) { '\\.(gif|ttf|eot)$': '@jupyterlab/testutils/lib/jest-file-mock.js' }, transform: { - '\\.svg$': 'jest-raw-loader', - '^.+\\.md?$': 'markdown-loader-jest' + '\\.svg$': 'jest-raw-loader' }, testTimeout: 10000, setupFiles: ['@jupyterlab/testutils/lib/jest-shim.js'], diff --git a/testutils/src/jest-file-mock.ts b/testutils/src/jest-file-mock.ts index 86059f3..85c6974 100644 --- a/testutils/src/jest-file-mock.ts +++ b/testutils/src/jest-file-mock.ts @@ -1 +1,6 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + module.exports = 'test-file-stub'; diff --git a/testutils/src/jest-shim.ts b/testutils/src/jest-shim.ts index 8eaeee3..c320d67 100644 --- a/testutils/src/jest-shim.ts +++ b/testutils/src/jest-shim.ts @@ -1,5 +1,14 @@ +/* + * 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 +const util = require('util'); +(global as any).TextDecoder = util.TextDecoder; +(global as any).TextEncoder = util.TextEncoder; + const fetchMod = ((window as any).fetch = require('node-fetch')); // tslint:disable-line (window as any).Request = fetchMod.Request; (window as any).Headers = fetchMod.Headers; @@ -29,7 +38,7 @@ const createContextualFragment = (html: string) => { /* no-op */ }, getBoundingClientRect: () => ({ right: 0 }), - getClientRects: (): ClientRect[] => [], + getClientRects: (): DOMRect[] => [], createContextualFragment }; }; diff --git a/testutils/src/json-to-html.d.ts b/testutils/src/json-to-html.d.ts index ef066f5..b87d42a 100644 --- a/testutils/src/json-to-html.d.ts +++ b/testutils/src/json-to-html.d.ts @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + // Type definitions for json2html v0.1.2 // https://github.com/frozzare/json-to-html // Definitions by: Steven Silvester diff --git a/testutils/src/mock.ts b/testutils/src/mock.ts index 2f7566c..f0c3626 100644 --- a/testutils/src/mock.ts +++ b/testutils/src/mock.ts @@ -58,7 +58,7 @@ export const KERNELSPECS: { [key: string]: KernelSpec.ISpecModel } = { '{connection_file}' ], display_name: 'R', - language: 'python', + language: 'r', metadata: {}, name: 'irkernel', resources: {} @@ -96,7 +96,7 @@ export const NOTEBOOK_PATHS: { [kernelName: string]: string[] } = { export function updateKernelStatus( sessionContext: ISessionContext, newStatus: KernelMessage.Status -) { +): void { const kernel = sessionContext.session!.kernel!; (kernel as any).status = newStatus; (sessionContext.statusChanged as any).emit(newStatus); @@ -170,6 +170,10 @@ export const KernelMock = jest.fn< ...jest.requireActual('@jupyterlab/services'), ...options, ...model, + model, + serverSettings: ServerConnection.makeSettings( + options.serverSettings as Partial + ), status: 'idle', spec: Promise.resolve(spec), dispose: jest.fn(), @@ -235,7 +239,7 @@ export const KernelMock = jest.fn< KernelMessage.IExecuteReplyMsg >; }) - } as any; // FIXME: fix the typing error this any cast is ignoring + }; // Add signals. const iopubMessageSignal = new Signal< Kernel.IKernelConnection, @@ -271,6 +275,7 @@ export const SessionConnectionMock = jest.fn< 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', @@ -279,11 +284,13 @@ export const SessionConnectionMock = jest.fn< }; const thisObject: Session.ISessionConnection = { ...jest.requireActual('@jupyterlab/services'), - id: UUID.uuid4(), ...options, model, ...model, kernel, + serverSettings: ServerConnection.makeSettings( + options.serverSettings as Partial + ), dispose: jest.fn(), changeKernel: jest.fn(partialModel => { return Private.changeKernel(kernel!, partialModel!); @@ -304,7 +311,7 @@ export const SessionConnectionMock = jest.fn< propertyChangedSignal.emit('type'); return Promise.resolve(); }) - } as any; // FIXME: fix the typing error this any cast is ignoring + }; const disposedSignal = new Signal( thisObject ); @@ -388,10 +395,9 @@ export const SessionContextMock = jest.fn< path: session.path, type: session.type, name: session.name, - kernel: session.kernel, session, dispose: jest.fn(), - initialize: jest.fn(() => Promise.resolve()), + initialize: jest.fn(() => Promise.resolve(false)), ready: Promise.resolve(), changeKernel: jest.fn(partialModel => { return Private.changeKernel( @@ -400,7 +406,7 @@ export const SessionContextMock = jest.fn< ); }), shutdown: jest.fn(() => Promise.resolve()) - } as any; // FIXME: fix the typing error this any cast is ignoring + }; const disposedSignal = new Signal(thisObject); @@ -523,7 +529,12 @@ export const ContentsManagerMock = jest.fn(() => { if (options?.content !== false) { const content: Contents.IModel[] = []; files.forEach(fileModel => { - if (PathExt.dirname(fileModel.path) == model.path) { + 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); } }); @@ -803,7 +814,7 @@ namespace Private { } // Get the kernel spec for kernel name - export function kernelSpecForKernelName(name: string) { + export function kernelSpecForKernelName(name: string): KernelSpec.ISpecModel { return KERNELSPECS[name]; } @@ -826,7 +837,7 @@ namespace Private { export function changeKernel( kernel: Kernel.IKernelConnection, partialModel: Partial - ): Promise { + ): Promise { if (partialModel.id) { const kernelIdx = KERNEL_MODELS.findIndex(model => { return model.id === partialModel.id; diff --git a/testutils/src/notebook-utils.ts b/testutils/src/notebook-utils.ts index 000ccf2..219e7ed 100644 --- a/testutils/src/notebook-utils.ts +++ b/testutils/src/notebook-utils.ts @@ -80,14 +80,17 @@ export namespace NBTestUtils { } ]; - 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 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 editorFactory = + editorServices.factoryService.newInlineEditor.bind( + editorServices.factoryService + ); export const mimeTypeService = editorServices.mimeTypeService; diff --git a/testutils/src/start_jupyter_server.ts b/testutils/src/start_jupyter_server.ts index 5a6f8b2..221f605 100644 --- a/testutils/src/start_jupyter_server.ts +++ b/testutils/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'; @@ -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 }); @@ -320,7 +327,7 @@ namespace Private { output.split('\n').forEach(line => { const baseUrlMatch = line.match(/(http:\/\/localhost:\d+\/[^?]*)/); if (baseUrlMatch) { - baseUrl = baseUrlMatch[1].replace('/lab', ''); + baseUrl = baseUrlMatch[1].replace('/doc', ''); PageConfig.setOption('baseUrl', baseUrl); } }); diff --git a/testutils/test/mock.spec.ts b/testutils/test/mock.spec.ts index 681c8e6..5687da9 100644 --- a/testutils/test/mock.spec.ts +++ b/testutils/test/mock.spec.ts @@ -98,7 +98,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 +124,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 +139,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 +180,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 +198,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(); }); }); @@ -262,21 +266,23 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const context = new Mock.SessionContextMock({}, null); - context.dispose(); + expect(() => { + context.dispose(); + }).not.toThrow(); }); }); describe('.initialize()', () => { it('should be a no-op', async () => { const context = new Mock.SessionContextMock({}, null); - await context.initialize(); + await expect(context.initialize()).resolves.not.toThrow(); }); }); describe('.ready', () => { it('should be a no-op', async () => { const context = new Mock.SessionContextMock({}, null); - await context.ready; + await expect(context.ready).resolves.not.toThrow(); }); }); @@ -292,7 +298,7 @@ describe('mock', () => { describe('.shutdown()', () => { it('should be a no-op', async () => { const context = new Mock.SessionContextMock({}, null); - await context.shutdown(); + await expect(context.shutdown()).resolves.not.toThrow(); }); }); }); @@ -463,7 +469,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const manager = new Mock.ContentsManagerMock(); - manager.dispose(); + expect(() => { + manager.dispose(); + }).not.toThrow(); }); }); }); @@ -523,7 +531,7 @@ describe('mock', () => { describe('.refreshRunning()', () => { it('should be a no-op', async () => { const manager = new Mock.SessionManagerMock(); - await manager.refreshRunning(); + await expect(manager.refreshRunning()).resolves.not.toThrow(); }); }); @@ -559,7 +567,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 +583,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 +611,9 @@ describe('mock', () => { describe('.dispose()', () => { it('should be a no-op', () => { const manager = new Mock.ServiceManagerMock(); - manager.dispose(); + expect(() => { + manager.dispose(); + }).not.toThrow(); }); }); }); diff --git a/testutils/test/start_jupyter_server.spec.ts b/testutils/test/start_jupyter_server.spec.ts index d2214cc..e246cb8 100644 --- a/testutils/test/start_jupyter_server.spec.ts +++ b/testutils/test/start_jupyter_server.spec.ts @@ -12,16 +12,19 @@ describe('JupyterServer', () => { 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(); }); 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 } }; diff --git a/testutils/tsconfig.json b/testutils/tsconfig.json index a59143f..5c62659 100644 --- a/testutils/tsconfig.json +++ b/testutils/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "module": "commonjs" + "module": "commonjs", + "types": ["node"] }, "include": ["src/*"], "references": [ diff --git a/testutils/tsconfig.test.json b/testutils/tsconfig.test.json index d9e4f2d..57a4268 100644 --- a/testutils/tsconfig.test.json +++ b/testutils/tsconfig.test.json @@ -34,36 +34,6 @@ }, { "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 9277447..793493b 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -11,6 +11,7 @@ "dev_mode/*", "docs/**/*", ".eslintrc.js", + ".eslintrc.typecheck.js", "examples/**/*", "galata/.eslintrc.js", "galata/*.config.js", @@ -21,7 +22,6 @@ "packages/services/examples/**/*", "packages/**/*.config.js", "packages/metapackage/build-doc-index.js", - "packages/**/stories/*", "scripts/*", "jupyterlab/*", "jupyterlab/staging/*", diff --git a/tsconfigdoc.json b/tsconfigdoc.json index e5e3a2f..a68e046 100644 --- a/tsconfigdoc.json +++ b/tsconfigdoc.json @@ -31,6 +31,12 @@ { "path": "./packages/attachments" }, + { + "path": "./packages/cell-toolbar" + }, + { + "path": "./packages/cell-toolbar-extension" + }, { "path": "./packages/cells" }, @@ -49,6 +55,12 @@ { "path": "./packages/codemirror-extension" }, + { + "path": "./packages/collaboration" + }, + { + "path": "./packages/collaboration-extension" + }, { "path": "./packages/completer" }, @@ -157,6 +169,12 @@ { "path": "./packages/logconsole-extension" }, + { + "path": "./packages/lsp" + }, + { + "path": "./packages/lsp-extension" + }, { "path": "./packages/mainmenu" }, @@ -169,6 +187,9 @@ { "path": "./packages/markdownviewer-extension" }, + { + "path": "./packages/markedparser-extension" + }, { "path": "./packages/mathjax2" }, diff --git a/typedoc.js b/typedoc.js index 6031c40..b9c01cc 100644 --- a/typedoc.js +++ b/typedoc.js @@ -1,3 +1,8 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + const fs = require('fs'); const packages = [ @@ -12,6 +17,8 @@ const packages = [ 'codeeditor', 'codemirror-extension', 'codemirror', + 'collaboration', + 'collaboration-extension', 'completer-extension', 'completer', 'console-extension', @@ -48,6 +55,7 @@ const packages = [ 'launcher', 'logconsole-extension', 'logconsole', + 'lsp-extension', 'mainmenu-extension', 'mainmenu', 'markdownviewer-extension', @@ -103,7 +111,8 @@ const entryPoints = packages const exclude = packages.flatMap(p => [`packages/${p}/test`]) + [ - 'packages/application-extension/src/index.tsx' + 'packages/application-extension/src/index.tsx', + 'examples/example.spec.ts' //'packages/*/test/*.spec.ts', ]; @@ -114,8 +123,9 @@ module.exports = { out: 'docs/api', // json: 'docs/api.json', readme: 'README.md', - theme: 'typedoc-theme', + theme: 'default', tsconfig: 'tsconfigdoc.json' + //plugin: "./typedoc-theme/lib/index.js" // theme: minimal, // excludePrivate: true, diff --git a/yarn.lock b/yarn.lock index 6f19143..66b0890 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,1244 +2,1196 @@ # 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.12.13", "@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.14.8", "@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" +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.1.0", "@babel/core@^7.10.2", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz" + integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.10" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.1.2" + json5 "^2.2.1" 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== +"@babel/generator@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.10.tgz" + integrity sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.18.10" + "@jridgewell/gen-mapping" "^0.3.2" 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== +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.18.6" -"@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== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.14.5" - "@babel/types" "^7.14.5" + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" -"@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== +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" 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== +"@babel/helper-create-class-features-plugin@^7.18.6": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz" + integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw== 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-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" -"@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== +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - regexpu-core "^4.7.1" + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" -"@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== +"@babel/helper-define-polyfill-provider@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz" + integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg== 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" + "@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" -"@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== +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== 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" + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@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.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + 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" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz" + integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz" + integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.10.tgz" + integrity sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ== + dependencies: + "@babel/helper-function-name" "^7.18.9" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" 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/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.10.tgz" + integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg== -"@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== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== 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/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz" + integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== 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/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" -"@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== +"@babel/plugin-proposal-async-generator-functions@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz" + integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew== dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" -"@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== +"@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== 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/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz" + integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== 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/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^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== +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== 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/helper-plugin-utils" "^7.18.9" "@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== +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz" + integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" "@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== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-object-rest-spread@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz" + integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q== dependencies: - "@babel/compat-data" "^7.14.7" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.18.8" -"@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== +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz" + integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" "@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== +"@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz" + integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== 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/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@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== +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" 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== +"@babel/plugin-syntax-import-assertions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz" + integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" "@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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== 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" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== 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== +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz" + integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" -"@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== +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== 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/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-block-scoping@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz" + integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-classes@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz" + integrity sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g== 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" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" 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== +"@babel/plugin-transform-computed-properties@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz" + integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-destructuring@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz" + integrity sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-for-of@^7.18.8": + version "7.18.8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-flow" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== 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/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.9" -"@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== +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-modules-amd@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz" + integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg== dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" 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== +"@babel/plugin-transform-modules-commonjs@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz" + integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.14.5" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" 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== +"@babel/plugin-transform-modules-systemjs@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz" + integrity sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A== 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/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-validator-identifier" "^7.18.6" 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== +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz" + integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" -"@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== +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.18.8": + version "7.18.8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz" + integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz" + integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + regenerator-transform "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz" + integrity sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.10.2": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz" + integrity sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@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.18.10" + "@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.18.9" + "@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.18.6" + "@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.18.9" + "@babel/plugin-transform-classes" "^7.18.9" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.18.9" + "@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.18.6" + "@babel/plugin-transform-modules-commonjs" "^7.18.6" + "@babel/plugin-transform-modules-systemjs" "^7.18.9" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.18.8" + "@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.18.9" + "@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.18.10" + babel-plugin-polyfill-corejs2 "^0.3.2" + babel-plugin-polyfill-corejs3 "^0.5.3" + babel-plugin-polyfill-regenerator "^0.4.0" + core-js-compat "^3.22.1" + semver "^6.3.0" -"@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== +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@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/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== +"@babel/runtime@^7.16.7", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + regenerator-runtime "^0.13.4" -"@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/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.10.tgz" + integrity sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + debug "^4.1.0" + globals "^11.1.0" -"@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== +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== dependencies: - "@babel/plugin-transform-react-jsx" "^7.14.5" + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" -"@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" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@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== +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + exec-sh "^0.3.2" + minimist "^1.2.0" -"@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== +"@codemirror/autocomplete@^6.0.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.1.0.tgz" + integrity sha512-wtO4O5WDyXhhCd4q4utDIDZxnQfmJ++3dGBCG9LMtI79+92OcA1DVk/n7BEupKmjIr8AzvptDz7YQ9ud6OkU+A== dependencies: - regenerator-transform "^0.14.2" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" -"@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== +"@codemirror/commands@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz" + integrity sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" -"@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== +"@codemirror/lang-cpp@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.1.tgz" + integrity sha512-46p3ohfhjzkLWJ3VwvzX0aqlXh8UkEqX1xo2Eds9l6Ql3uDoxI2IZEjR9cgJaGOZTXCkDzQuQH7sfYAxMvzLjA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/cpp" "^1.0.0" -"@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== +"@codemirror/lang-css@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz" + integrity sha512-jBqc+BTuwhNOTlrimFghLlSrN6iFuE44HULKWoR4qKYObhOIl9Lci1iYj6zMIte1XTQmZguNvjXMyr43LUKwSw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/css" "^1.0.0" -"@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== +"@codemirror/lang-html@^6.0.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.1.0.tgz" + integrity sha512-gA7NmJxqvnhwza05CvR7W/39Ap9r/4Vs9uiC0IeFYo1hSlJzc/8N6Evviz6vTW1x8SpHcRYyqKOf6rpl6LfWtg== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/lang-css" "^6.0.0" + "@codemirror/lang-javascript" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/html" "^1.0.0" + +"@codemirror/lang-java@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.0.tgz" + integrity sha512-aeWq+ikUS6Eubk6RBbiMgxuBIT4Ih8Asb1qc2pSiMcstrwr4ODbazPXsBHbLBYg3aObvFyOm2bNQncbQJjZ3sQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/java" "^1.0.0" -"@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== +"@codemirror/lang-javascript@^6.0.0": + version "6.0.2" + resolved "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz" + integrity sha512-BZRJ9u/zl16hLkSpDAWm73mrfIR7HJrr0lvnhoSOCQVea5BglguWI/slxexhvUb0CB5cXgKWuo2bM+N9EhIaZw== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.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" + +"@codemirror/lang-json@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz" + integrity sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/json" "^1.0.0" -"@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== +"@codemirror/lang-markdown@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.0.1.tgz" + integrity sha512-pHPQuRwf9cUrmkmsTHRjtS9ZnGu3fA9YzAdh2++d+L9wbfnC2XbKh0Xvm/0YiUjdCnoCx9wDFEoCuAnkqKWLIw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/lang-html" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/markdown" "^1.0.0" -"@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== +"@codemirror/lang-php@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.0.tgz" + integrity sha512-96CEjq0xEgbzc6bdFPwILPfZ6m8917JRbh2oPszZJABlYxG4Y+eYjtYkUTDb4yuyjQKyigHoeGC6zoIOYA1NWA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-typescript" "^7.14.5" + "@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" -"@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== +"@codemirror/lang-python@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.0.1.tgz" + integrity sha512-w2jTSY+LgXnK7iIBLgMxk6xtJhZHkcxcGGveuq9zYmncURmOTFXKnDvBaBClNIHKgjkHXZqGK8ZduCMK23hZPA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/python" "^1.0.0" -"@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== +"@codemirror/lang-rust@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.0.tgz" + integrity sha512-VQql3Qk1BwoXb3SUkeWll/EEwhsgQWc1bpia7CFqqp2PhQBb5A6r4Vj2JCkU/nE6A7TDPSGHTOoqJSG5s/VXtQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/rust" "^1.0.0" -"@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== +"@codemirror/lang-sql@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.0.0.tgz" + integrity sha512-mq4NwTDbbo7QZktfgPsS+ms0FmAceH4WM2jLbgf+N28FoKUy0JzGe3XJymgnTewXnNUwujKBxArQzibxSDdVyQ== 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" + "@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" -"@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== +"@codemirror/lang-wast@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-wast/-/lang-wast-6.0.0.tgz" + integrity sha512-vSbtLrxuB95PC5LJ+yszKVmBUkLmMdowNFjjn0e+LHeBzvpdQJHVomgE76UUFeZGW+Ht0VfM6rxEd9SL85FuhA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-flow-strip-types" "^7.14.5" + "@codemirror/language" "^6.0.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" -"@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== +"@codemirror/lang-xml@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.0.tgz" + integrity sha512-M/HLWxIiP956xGjtrxkeHkCmDGVQGKu782x8pOH5CLJIMkWtiB1DWfDoDHqpFjdEE9dkfcqPWvYfVi6GbhuXEg== 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" + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/xml" "^1.0.0" -"@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== +"@codemirror/language@^6.0.0": + version "6.2.1" + resolved "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz" + integrity sha512-MC3svxuvIj0MRpFlGHxLS6vPyIdbTr2KKPEW46kCoCXw2ktb4NTkpkPBI/lSP/FoNXLCBJ0mrnUi1OoZxtpW1Q== 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" + "@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" -"@babel/preset-typescript@^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== +"@codemirror/legacy-modes@^6.0.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.1.0.tgz" + integrity sha512-V/PgGpndkZeTn3Hdlg/gd8MLFdyvTCIX+iwJzjUw5iNziWiNsAY8X0jvf7m3gSfxnKkNzmid6l0g4rYSpiDaCw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-typescript" "^7.15.0" + "@codemirror/language" "^6.0.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== +"@codemirror/lint@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz" + integrity sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA== 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" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" -"@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== +"@codemirror/search@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/search/-/search-6.0.1.tgz" + integrity sha512-uOinkOrM+daMduCgMPomDfKLr7drGHB4jHl3Vq6xY2WRlL7MkNsBE0b+XHYa/Mee2npsJOgwvkW4n1lMFeBW2Q== dependencies: - regenerator-runtime "^0.13.4" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" -"@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" +"@codemirror/state@^6.0.0": + version "6.1.1" + resolved "https://registry.npmjs.org/@codemirror/state/-/state-6.1.1.tgz" + integrity sha512-2s+aXsxmAwnR3Rd+JDHPG/1lw0YsA9PEwl7Re88gHJHGfxyfEzKBmsN4rr53RyPIR4lzbbhJX0DCq0WlqlBIRw== -"@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== +"@codemirror/view@^6.0.0": + version "6.1.2" + resolved "https://registry.npmjs.org/@codemirror/view/-/view-6.1.2.tgz" + integrity sha512-puUydfKwfmOo+ixtuB+uN/ZpcteEYSnpjHmMaow1sOQhNICsKtGBup3i9ybVqyzDagARRYzSHTWjbdeHqmn31w== 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" + "@codemirror/state" "^6.0.0" + style-mod "^4.0.0" + w3c-keyname "^2.2.4" -"@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" +"@csstools/selector-specificity@^2.0.1": + version "2.0.2" + resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz" + integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== "@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== + version "0.5.7" + resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@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== +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - lodash "^4.17.19" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" 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== + version "5.15.4" + resolved "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz" + integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg== -"@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== +"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@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" + resolved "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz" 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== +"@isaacs/string-locale-compare@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz" + integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ== "@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" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -1250,12 +1202,12 @@ "@istanbuljs/schema@^0.1.2": version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" 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" + resolved "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz" integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: "@jest/types" "^26.6.2" @@ -1267,7 +1219,7 @@ "@jest/core@^26.6.3": version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + resolved "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz" integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: "@jest/console" "^26.6.2" @@ -1301,7 +1253,7 @@ "@jest/environment@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz" integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: "@jest/fake-timers" "^26.6.2" @@ -1311,7 +1263,7 @@ "@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" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz" integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: "@jest/types" "^26.6.2" @@ -1323,7 +1275,7 @@ "@jest/globals@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz" integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== dependencies: "@jest/environment" "^26.6.2" @@ -1332,7 +1284,7 @@ "@jest/reporters@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz" integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -1364,7 +1316,7 @@ "@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" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz" integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" @@ -1373,7 +1325,7 @@ "@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" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz" integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: "@jest/console" "^26.6.2" @@ -1383,7 +1335,7 @@ "@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" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz" integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: "@jest/test-result" "^26.6.2" @@ -1394,7 +1346,7 @@ "@jest/transform@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz" integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" @@ -1415,7 +1367,7 @@ "@jest/types@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz" integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" @@ -1424,847 +1376,1004 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jest/types@^27.2.5": - version "27.2.5" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.2.5.tgz#420765c052605e75686982d24b061b4cbba22132" - integrity sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ== +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" -"@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" +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@lerna/add@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/add/-/add-5.4.3.tgz" + integrity sha512-wBjBHX/A0nSiVGJDq5wNpqR+zrxKFREeKrqvIXGmAgcwpDjp76JLVhdSdQns+X+AYsf13NFaNhBqfGlF5SZNnQ== + dependencies: + "@lerna/bootstrap" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/npm-conf" "5.4.3" + "@lerna/validation-error" "5.4.3" dedent "^0.7.0" - npm-package-arg "^8.1.0" + npm-package-arg "8.1.1" p-map "^4.0.0" - pacote "^11.2.6" + pacote "^13.6.1" 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" +"@lerna/bootstrap@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-5.4.3.tgz" + integrity sha512-9mruEpXD2p8mG9Feak0QzU+JcROsJ8J0MvY7gTGtUqQJqBIA6HGEYXQueHbcl+jGdZyTZOz139KsavPui55QEQ== + dependencies: + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/has-npm-version" "5.4.3" + "@lerna/npm-install" "5.4.3" + "@lerna/package-graph" "5.4.3" + "@lerna/pulse-till-done" "5.4.3" + "@lerna/rimraf-dir" "5.4.3" + "@lerna/run-lifecycle" "5.4.3" + "@lerna/run-topologically" "5.4.3" + "@lerna/symlink-binary" "5.4.3" + "@lerna/symlink-dependencies" "5.4.3" + "@lerna/validation-error" "5.4.3" + "@npmcli/arborist" "5.3.0" dedent "^0.7.0" get-port "^5.1.1" multimatch "^5.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" + npm-package-arg "8.1.1" + npmlog "^6.0.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== +"@lerna/changed@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/changed/-/changed-5.4.3.tgz" + integrity sha512-q1ARClN0pLZ53hBPiR4TJB6GGq17Yhwb6iKwQryZBWuOEc87NqqRtIPWswk5NISj2qcPQlbyrnB3RshwLkyo7w== dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" + "@lerna/collect-updates" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/listable" "5.4.3" + "@lerna/output" "5.4.3" -"@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== +"@lerna/check-working-tree@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-5.4.3.tgz" + integrity sha512-OnGqIDW8sRcAQDV8mdtvYIh0EIv2FXm+4/qKAveFhyDkWWpnUF/ZSIa/CFVHYoKFFzb5WOBouml2oqWPyFHhbA== dependencies: - "@lerna/collect-uncommitted" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/validation-error" "4.0.0" + "@lerna/collect-uncommitted" "5.4.3" + "@lerna/describe-ref" "5.4.3" + "@lerna/validation-error" "5.4.3" -"@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== +"@lerna/child-process@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/child-process/-/child-process-5.4.3.tgz" + integrity sha512-p7wJ8QT8kXHk4EAy/oyjCD603n1F61Tm4l6thF1h9MAw3ejSvvUZ0BKSg9vPoZ/YMAC9ZuVm1mFsyoi5RlvIHw== 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" +"@lerna/clean@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/clean/-/clean-5.4.3.tgz" + integrity sha512-Kl04A5NqywbBf7azSt9UJqHzRCXogHNpEh3Yng5+Y4ggunP4zVabzdoYGdggS4AsbDuIOKECx9BmCiDwJ4Qv8g== + dependencies: + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/prompt" "5.4.3" + "@lerna/pulse-till-done" "5.4.3" + "@lerna/rimraf-dir" "5.4.3" 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== +"@lerna/cli@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/cli/-/cli-5.4.3.tgz" + integrity sha512-avnRUZ51nSZMR+tOcMQZ61hnVbDNdmyaVRxfSLByH5OFY+KPnfaTPv1z4ub+rEtV2NTI5DYWAqxupNGLuu9bQQ== dependencies: - "@lerna/global-options" "4.0.0" + "@lerna/global-options" "5.4.3" dedent "^0.7.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/collect-uncommitted@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-5.4.3.tgz" + integrity sha512-/0u95DbwP1+orGifkPRqaIqD8Ui2vpy9KmeuHTui+4iR/ZvZbgIouMdOhH+fU9e5hfLF6geUKnEFjL+Lxa4qdg== dependencies: - "@lerna/child-process" "4.0.0" + "@lerna/child-process" "5.4.3" chalk "^4.1.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/collect-updates@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-5.4.3.tgz" + integrity sha512-TU3+hcwqHWKSK0J+NWNo5pjP7nnCzhnFfL/UfCG6oNAUb6PnmKSgZ9NqjOXja1WjJPrtFDIGoIYzLJZCePFyLw== dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/describe-ref" "4.0.0" + "@lerna/child-process" "5.4.3" + "@lerna/describe-ref" "5.4.3" minimatch "^3.0.4" - npmlog "^4.1.2" + npmlog "^6.0.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" +"@lerna/command@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/command/-/command-5.4.3.tgz" + integrity sha512-xBdbqcvHeWltH4QvWcmH9dKjWzD+KXfhSP0NBgwED8ZNMxSuzBz2OS3Ps8KbLemXNP8P0yhjoPgitGmxxeY/ow== + dependencies: + "@lerna/child-process" "5.4.3" + "@lerna/package-graph" "5.4.3" + "@lerna/project" "5.4.3" + "@lerna/validation-error" "5.4.3" + "@lerna/write-log-file" "5.4.3" clone-deep "^4.0.1" dedent "^0.7.0" execa "^5.0.0" is-ci "^2.0.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/conventional-commits@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-5.4.3.tgz" + integrity sha512-GHZdpCUMqalO692O7Mqj5idYftZWaCylb4TSPkHEU8xSfxtufp8lM+Q8Xxv35ymzs0pBrmzSLZIpIMQ9awDABg== dependencies: - "@lerna/validation-error" "4.0.0" + "@lerna/validation-error" "5.4.3" conventional-changelog-angular "^5.0.12" - conventional-changelog-core "^4.2.2" + conventional-changelog-core "^4.2.4" 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" + npm-package-arg "8.1.1" + npmlog "^6.0.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== +"@lerna/create-symlink@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-5.4.3.tgz" + integrity sha512-QxmKCHA5woed/qJjKNkOSgkbhhmPV3g61F499uVwPtyPivn9Y2mbeVPMQrLkb0CL9M6aJ7vE4fi6T5XMqsbNpg== dependencies: - cmd-shim "^4.1.0" + cmd-shim "^5.0.0" fs-extra "^9.1.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/create@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/create/-/create-5.4.3.tgz" + integrity sha512-VLrcfjBNzhUie5tLWSEa203BljirEG7OH62lgoLqR9qA/FVozoWrRKmly/EVw8Q7+5UNw/ciTzXnbm0BPXl6tg== dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" + "@lerna/child-process" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/npm-conf" "5.4.3" + "@lerna/validation-error" "5.4.3" 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" + init-package-json "^3.0.2" + npm-package-arg "8.1.1" p-reduce "^2.1.0" - pacote "^11.2.6" + pacote "^13.6.1" 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" + validate-npm-package-name "^4.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" +"@lerna/describe-ref@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-5.4.3.tgz" + integrity sha512-g3R5exjZy5MOcMPzgU8+t7sGEt4gGMKQLUFfg5NAceera6RGWUieY8OWL6jlacgyM4c8iyh15Tu14YwzL2DiBA== + dependencies: + "@lerna/child-process" "5.4.3" + npmlog "^6.0.2" + +"@lerna/diff@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/diff/-/diff-5.4.3.tgz" + integrity sha512-MJKvy/XC2RpS/gqg7GguQsBv5rZm+S5P/kfnqhapXCniGviZfq+JfY5TQCsAP9umiybR2sB004K1Z7heyU8uMA== + dependencies: + "@lerna/child-process" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/validation-error" "5.4.3" + npmlog "^6.0.2" + +"@lerna/exec@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/exec/-/exec-5.4.3.tgz" + integrity sha512-BLrva/KV6JWTV+7h7h+NQDsxpz0z1Nh99BUqqvZDzGIKMey4c1fo+CQGac77TsAophnv0ieFgHkSmrC6NXJa9g== + dependencies: + "@lerna/child-process" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/profiler" "5.4.3" + "@lerna/run-topologically" "5.4.3" + "@lerna/validation-error" "5.4.3" 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== +"@lerna/filter-options@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-5.4.3.tgz" + integrity sha512-581GE81BSWgS9za4tBv1nwZ2ImgH7UO3xil1b7xogvc/iGwM0MgOwt9f1MrS5ZOliNnme4cSZEGFe+QWPXCE4A== dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/filter-packages" "4.0.0" + "@lerna/collect-updates" "5.4.3" + "@lerna/filter-packages" "5.4.3" dedent "^0.7.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/filter-packages@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-5.4.3.tgz" + integrity sha512-W5OVMUjXh/Zii17FCSbIf/6Q3Bo5ETMAWMZ6EpHSU99M0kdvgpjXj3VUSjiCzwccqIa2EZjaua0RWSbOtfZCVg== dependencies: - "@lerna/validation-error" "4.0.0" + "@lerna/validation-error" "5.4.3" multimatch "^5.0.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/get-npm-exec-opts@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-5.4.3.tgz" + integrity sha512-q/3zQvlwTpAh6HVtVGOTuCGIgkhtCPK9CcHRo09c0Q3LQk5MsZYkPmJe0ujU1Gf7pILzQA5tnCy56eWT5uMPUg== dependencies: - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/get-packed@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-5.4.3.tgz" + integrity sha512-y97plqJmrTwnZE9EH0MhtwnVHOF/revnH95fD2UyUpGrxdAFvbE7rs3A9zrSxurFLn4q6qWBKONwQLccQSTBTA== dependencies: fs-extra "^9.1.0" - ssri "^8.0.1" + ssri "^9.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== +"@lerna/github-client@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/github-client/-/github-client-5.4.3.tgz" + integrity sha512-P/i64IUDw72YvS5lTciCLAxvjliN2lZSDZSqH59kQ4m2dma0dChiLTreq1Ei8xyY124oacARwxxQCN95m2u3nw== dependencies: - "@lerna/child-process" "4.0.0" + "@lerna/child-process" "5.4.3" "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^18.1.0" - git-url-parse "^11.4.4" - npmlog "^4.1.2" + "@octokit/rest" "^19.0.3" + git-url-parse "^12.0.0" + npmlog "^6.0.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== +"@lerna/gitlab-client@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-5.4.3.tgz" + integrity sha512-EEr5OkdiS7ev2X9jaknr3UUksPajij1nGFFhPXpAexAEkJYSRjdSvfPtd4ssTViIHMGHKMcNcGrMW+ESly1lpw== dependencies: node-fetch "^2.6.1" - npmlog "^4.1.2" + npmlog "^6.0.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/global-options@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/global-options/-/global-options-5.4.3.tgz" + integrity sha512-e0TVIHLl0IULJWfLA9uGOIYnI3MVAjTp9I0p/9u3fC62dQxJBhoy5/9+y2zuu85MTB+4XTVi2m8G99H9pfBhMA== -"@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== +"@lerna/has-npm-version@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-5.4.3.tgz" + integrity sha512-Vu5etw5vXEbYLOO26lO3u5gEjX9vWUjqLTQfNEnJxflaH9JWw2NNJ/6nXG0hqc8kEmMdhabrw+FHSKaO9ZQygw== dependencies: - "@lerna/child-process" "4.0.0" + "@lerna/child-process" "5.4.3" 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" +"@lerna/import@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/import/-/import-5.4.3.tgz" + integrity sha512-SRUyITjhqbN7JOrUHskaqbppiq8yqpSLw1+tseT3D3HdYQQjvQzR1GjBVm+LZKlHRi9qqku9fqUNQf9AqbtysA== + dependencies: + "@lerna/child-process" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/prompt" "5.4.3" + "@lerna/pulse-till-done" "5.4.3" + "@lerna/validation-error" "5.4.3" 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== +"@lerna/info@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/info/-/info-5.4.3.tgz" + integrity sha512-cO0jWK2zcU9fsnoR2aqYU1IqNxWBkLvvQcTiodPqMsTAVh2F8cbwUXptWJyvsyCkKqO86axa7h6AbeF9rHRj0g== dependencies: - "@lerna/command" "4.0.0" - "@lerna/output" "4.0.0" + "@lerna/command" "5.4.3" + "@lerna/output" "5.4.3" 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== +"@lerna/init@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/init/-/init-5.4.3.tgz" + integrity sha512-cicNfMuswF+8S5RhbvCnXIrdNWTS5/ajwGYOv85x/Gu2FOJ1eqJ4W4Ai6ybANBefErE4+7aSGl/kt/+sRvTeTw== dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" + "@lerna/child-process" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/project" "5.4.3" 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== +"@lerna/link@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/link/-/link-5.4.3.tgz" + integrity sha512-DY6PQYE2g1a5QGDXCoajr8hl87m83vmfUIz1342x1qwWHmfRLfS3KTPPfa5bsZk/ABVOrqjjz/v3m4SEJ4LC5A== dependencies: - "@lerna/command" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" + "@lerna/command" "5.4.3" + "@lerna/package-graph" "5.4.3" + "@lerna/symlink-dependencies" "5.4.3" 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== +"@lerna/list@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/list/-/list-5.4.3.tgz" + integrity sha512-VEoJfobof7Welp+1yX6gm0EtpZw9vyztGvTtOeHQ1fhfW88oav03Qoi/hk1qZXPf7/hVZrJKEmSJ4etxsbZ3/g== dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/listable" "5.4.3" + "@lerna/output" "5.4.3" -"@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== +"@lerna/listable@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/listable/-/listable-5.4.3.tgz" + integrity sha512-VcJMw+z84Rj1nLIso474+veFx0tCH9Jas02YXx9cgAnaK1IRP0BI9O0vccQIZ+2Rb62VLiFGzyCJIyKyhcGZHw== dependencies: - "@lerna/query-graph" "4.0.0" + "@lerna/query-graph" "5.4.3" chalk "^4.1.0" - columnify "^1.5.4" + columnify "^1.6.0" -"@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== +"@lerna/log-packed@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-5.4.3.tgz" + integrity sha512-pFEBaj5JOf44+kOV6eiFHAfEULC6NhHJHHFwkljL1WNcx/+46aOADY9LrjmVtp8uPWv3fMCb3ZGcxuGebz1lYA== dependencies: byte-size "^7.0.0" - columnify "^1.5.4" + columnify "^1.6.0" has-unicode "^2.0.1" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/npm-conf@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-5.4.3.tgz" + integrity sha512-iQrrZHxAXqogfCpQvC/ac42/gR3osT+WN2FFB1gjVYYFBMZto5mlpcvyzH8rb75OJfak8iDtOYHUymmwSda1jw== 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== +"@lerna/npm-dist-tag@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-5.4.3.tgz" + integrity sha512-LnbD6xrnrmMdXH/nntyd/xJueKZGhCv3YLWK9F6YQdmUoeWY+W7eckmdd8LKL6ZqupyeLxgn0NKwiJ5wxf0F2w== dependencies: - "@lerna/otplease" "4.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" + "@lerna/otplease" "5.4.3" + npm-package-arg "8.1.1" + npm-registry-fetch "^13.3.0" + npmlog "^6.0.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== +"@lerna/npm-install@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-5.4.3.tgz" + integrity sha512-MPXYQ1r/UMV9x+6F2VEk3miHOw4fn+G4zN11PGB5nWmuaT4uq7rPoudkdRvMRqm6bK0NpL/trssSb12ERzevqg== dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" + "@lerna/child-process" "5.4.3" + "@lerna/get-npm-exec-opts" "5.4.3" fs-extra "^9.1.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" + npm-package-arg "8.1.1" + npmlog "^6.0.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== +"@lerna/npm-publish@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-5.4.3.tgz" + integrity sha512-yfwtTWYRace2oJK+a7nVUs7HubypgoA1fEZ6JUZFKVkq54C8tDdyYz4EtTtiFr7WMjP8p3NWxh7RNh7Tyx7ckQ== dependencies: - "@lerna/otplease" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" + "@lerna/otplease" "5.4.3" + "@lerna/run-lifecycle" "5.4.3" fs-extra "^9.1.0" - libnpmpublish "^4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" + libnpmpublish "^6.0.4" + npm-package-arg "8.1.1" + npmlog "^6.0.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" + read-package-json "^5.0.1" + +"@lerna/npm-run-script@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-5.4.3.tgz" + integrity sha512-xb6YAxAxGDBPlpZtjDPlM9NAgIcNte31iuGpG0I5eTYqBppKNZ7CQ8oi76qptrLyrK/ug9kqDIGti5OgyAMihQ== + dependencies: + "@lerna/child-process" "5.4.3" + "@lerna/get-npm-exec-opts" "5.4.3" + npmlog "^6.0.2" + +"@lerna/otplease@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/otplease/-/otplease-5.4.3.tgz" + integrity sha512-iy+NpqP9UcB8a0W3Nhq20x2gWSRQcmkOb25qSJj7f5AisCwGWypYlD6RZ9NqCzUD7KEbAaydEEyhoPw9dQRFmg== + dependencies: + "@lerna/prompt" "5.4.3" + +"@lerna/output@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/output/-/output-5.4.3.tgz" + integrity sha512-y/skSk0jMxPlJ1gpQwmKiMdElbznOMCYdCi170wfj3esby+fr8eULiwx7wUy3K+YtEGp7JS6TUjXb4zm9O0rMw== + dependencies: + npmlog "^6.0.2" + +"@lerna/pack-directory@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-5.4.3.tgz" + integrity sha512-47vsQem4Jr1W7Ce03RKihprBFLh2Q+VKgIcQGPec764i5uv3QWHzqK//da7+fmHr86qusinHvCIV7X3pXcohWg== + dependencies: + "@lerna/get-packed" "5.4.3" + "@lerna/package" "5.4.3" + "@lerna/run-lifecycle" "5.4.3" + "@lerna/temp-write" "5.4.3" + npm-packlist "^5.1.1" + npmlog "^6.0.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== +"@lerna/package-graph@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-5.4.3.tgz" + integrity sha512-8eyAS+hb+K/+1Si2UNh4KPaLFdgTgdrRcsuTY7aKaINyrzoLTArAKPk4dQZTH1d0SUWtFzicvWixkkzq21QuOw== 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" + "@lerna/prerelease-id-from-version" "5.4.3" + "@lerna/validation-error" "5.4.3" + npm-package-arg "8.1.1" + npmlog "^6.0.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== +"@lerna/package@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/package/-/package-5.4.3.tgz" + integrity sha512-EIw82v4ijzS3qRCSKHNSJ/UTnFDroaEp6mj7pzLO6lIrAqg7MgtKeThMhzEAMvF4yNB7BL+UR+dZ0jI47WgQJQ== dependencies: load-json-file "^6.2.0" - npm-package-arg "^8.1.0" + npm-package-arg "8.1.1" 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== +"@lerna/prerelease-id-from-version@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-5.4.3.tgz" + integrity sha512-bXsBCv/VJrWXz2usnk52TtTb4dsXSeYDI2U1N2z/DssFKlOpH7xL1mKWC4OXE2XBqb9I49sDPfZzN8BxTfJdJQ== 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== +"@lerna/profiler@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/profiler/-/profiler-5.4.3.tgz" + integrity sha512-6otMDwCzfWszV0K7RRjlF5gibLZt1ay+NmtrhL7TZ7PSizIJXlf6HxZiYodGgjahKAdGxx34H9XyToVzOLdg3w== dependencies: fs-extra "^9.1.0" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/project@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/project/-/project-5.4.3.tgz" + integrity sha512-j2EeuwdbHsL++jy0s2ShDbdOPirPOL/FNMRf7Qtwl4pEWoOiSYmv/LnIt2pV7cwww9Lx8Y682/7CQwlXdgrrMw== dependencies: - "@lerna/package" "4.0.0" - "@lerna/validation-error" "4.0.0" + "@lerna/package" "5.4.3" + "@lerna/validation-error" "5.4.3" 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" + npmlog "^6.0.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" +"@lerna/prompt@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/prompt/-/prompt-5.4.3.tgz" + integrity sha512-VqrTgnbm1H24aYacXmZ2z7atHO6W4NamvwHroGRFqiM34dCLQh8S22X5mNnb4nX5lgfb+doqcxBtOi91vqpJ2g== + dependencies: + inquirer "^8.2.4" + npmlog "^6.0.2" + +"@lerna/publish@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/publish/-/publish-5.4.3.tgz" + integrity sha512-SYziRvRwahzbM0A4T63FfQsk2i33cIauKXlJz6t3GQZvVzUFb0gD/baVas2V7Fs/Ty1oCqtmDKB/ABTznWYwGg== + dependencies: + "@lerna/check-working-tree" "5.4.3" + "@lerna/child-process" "5.4.3" + "@lerna/collect-updates" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/describe-ref" "5.4.3" + "@lerna/log-packed" "5.4.3" + "@lerna/npm-conf" "5.4.3" + "@lerna/npm-dist-tag" "5.4.3" + "@lerna/npm-publish" "5.4.3" + "@lerna/otplease" "5.4.3" + "@lerna/output" "5.4.3" + "@lerna/pack-directory" "5.4.3" + "@lerna/prerelease-id-from-version" "5.4.3" + "@lerna/prompt" "5.4.3" + "@lerna/pulse-till-done" "5.4.3" + "@lerna/run-lifecycle" "5.4.3" + "@lerna/run-topologically" "5.4.3" + "@lerna/validation-error" "5.4.3" + "@lerna/version" "5.4.3" 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" + libnpmaccess "^6.0.3" + npm-package-arg "8.1.1" + npm-registry-fetch "^13.3.0" + npmlog "^6.0.2" p-map "^4.0.0" p-pipe "^3.1.0" - pacote "^11.2.6" + pacote "^13.6.1" 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== +"@lerna/pulse-till-done@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-5.4.3.tgz" + integrity sha512-Twy0UmVtyFzC+sLDnuY0u37Xu17WAP7ysQ7riaLx9KhO0M9MZvoY+kDF/hg0K204tZi0dr6R5eLGEUd+Xkg9Rw== dependencies: - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/query-graph@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-5.4.3.tgz" + integrity sha512-eiRsEPg+t2tN9VWXSAj2y0zEphPrOz6DdYw/5ntVFDecIfoANxGKcCkOTqb3PnaC8BojI64N3Ju+i41jcO0mLw== dependencies: - "@lerna/package-graph" "4.0.0" + "@lerna/package-graph" "5.4.3" -"@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== +"@lerna/resolve-symlink@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-5.4.3.tgz" + integrity sha512-BzqinKmTny70KgSBAaVgdLHaVR3WXRVk5EDbQHB73qg4dHiyYrzvDBqkaKzv1K1th8E4LdQQXf5LiNEbfU/1Bg== dependencies: fs-extra "^9.1.0" - npmlog "^4.1.2" - read-cmd-shim "^2.0.0" + npmlog "^6.0.2" + read-cmd-shim "^3.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== +"@lerna/rimraf-dir@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-5.4.3.tgz" + integrity sha512-gBraUVczKk4Jik1+qCj4jtQ53l1zmWmMoH7A11ifYI60Dg7Mc6iQcIZOIj6siD5TSOtSCy7qePu3VyXBOIquvQ== dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" + "@lerna/child-process" "5.4.3" + npmlog "^6.0.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== +"@lerna/run-lifecycle@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-5.4.3.tgz" + integrity sha512-XKUfELNjkR6EUg+Xh92s1etjNvCbTBw20QMXDsyGSipHcLr7huXjC0D2/4/+j8/N5sz/rg+JufQfc1ldtpOU0A== dependencies: - "@lerna/npm-conf" "4.0.0" - npm-lifecycle "^3.1.5" - npmlog "^4.1.2" + "@lerna/npm-conf" "5.4.3" + "@npmcli/run-script" "^4.1.7" + npmlog "^6.0.2" + p-queue "^6.6.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== +"@lerna/run-topologically@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-5.4.3.tgz" + integrity sha512-9bT8mJ0RICIk16l8L9jRRqSXGSiLEKUd50DLz5Tv0EdOKD+prwffAivCpVMYF9tdD5UaQzDAK/VzFdS5FEzPQg== dependencies: - "@lerna/query-graph" "4.0.0" + "@lerna/query-graph" "5.4.3" 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" +"@lerna/run@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/run/-/run-5.4.3.tgz" + integrity sha512-PyHOYCsuJ+5r9ymjtwbQCbMMebVhaZ7Xy4jNpL9kqIvmdxe1S5QTP6Vyc6+RAvUtx0upP++0MFFA8CbZ1ZwOcw== + dependencies: + "@lerna/command" "5.4.3" + "@lerna/filter-options" "5.4.3" + "@lerna/npm-run-script" "5.4.3" + "@lerna/output" "5.4.3" + "@lerna/profiler" "5.4.3" + "@lerna/run-topologically" "5.4.3" + "@lerna/timer" "5.4.3" + "@lerna/validation-error" "5.4.3" 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== +"@lerna/symlink-binary@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-5.4.3.tgz" + integrity sha512-iXBijyb1+NiOeifnRsbicSju6/FGtv6hvNny2lbjyr0EJ8jMz6JaoQ6eep9yXhgaNRJND1Pw9JBiCv6EhhcyCw== dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/package" "4.0.0" + "@lerna/create-symlink" "5.4.3" + "@lerna/package" "5.4.3" 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== +"@lerna/symlink-dependencies@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-5.4.3.tgz" + integrity sha512-9fK3fIl6wyihyfKhDUquiAx8JoMjctBJ7zhLjrgOon5Ua2fyc+mVp9fTWsjHtv7IaC/TeP9oA4/IcBtdr2xieg== dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/resolve-symlink" "4.0.0" - "@lerna/symlink-binary" "4.0.0" + "@lerna/create-symlink" "5.4.3" + "@lerna/resolve-symlink" "5.4.3" + "@lerna/symlink-binary" "5.4.3" 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== +"@lerna/temp-write@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/temp-write/-/temp-write-5.4.3.tgz" + integrity sha512-HgAVNmKfeRKm4QPFGFfmzVC/lA2jv5QpMXPPDahoBEI6BhYtMmHiUWQan6dfsCoSf65xDd+9NTESya9AOSbN2w== 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" + graceful-fs "^4.1.15" + is-stream "^2.0.0" + make-dir "^3.0.0" + temp-dir "^1.0.0" + uuid "^8.3.2" + +"@lerna/timer@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/timer/-/timer-5.4.3.tgz" + integrity sha512-0NwrCxug6pmSAuPaAHNr5VRGw7+nqikoIpwx6RViJiOD+UYFf3k955fngtSX2JhETR/7it9ncgpbaLvlxusx9g== + +"@lerna/validation-error@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-5.4.3.tgz" + integrity sha512-edf9vbQaDViffhHqL/wHdGs83RV7uJ4N5E3VEpjXefWIUfgmw9wYjkX338WYUh/XqDYbSV6C1M8A24FT3/0uzw== + dependencies: + npmlog "^6.0.2" + +"@lerna/version@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/version/-/version-5.4.3.tgz" + integrity sha512-a6Q+o1fZbOg/GVG8QtvfyOpX0sZ38bbI9hSJU5YMf99YKdyzp80dDDav+IGMxIaZSj08HJ1pPyXOLR27I8fTUQ== + dependencies: + "@lerna/check-working-tree" "5.4.3" + "@lerna/child-process" "5.4.3" + "@lerna/collect-updates" "5.4.3" + "@lerna/command" "5.4.3" + "@lerna/conventional-commits" "5.4.3" + "@lerna/github-client" "5.4.3" + "@lerna/gitlab-client" "5.4.3" + "@lerna/output" "5.4.3" + "@lerna/prerelease-id-from-version" "5.4.3" + "@lerna/prompt" "5.4.3" + "@lerna/run-lifecycle" "5.4.3" + "@lerna/run-topologically" "5.4.3" + "@lerna/temp-write" "5.4.3" + "@lerna/validation-error" "5.4.3" chalk "^4.1.0" dedent "^0.7.0" load-json-file "^6.2.0" minimatch "^3.0.4" - npmlog "^4.1.2" + npmlog "^6.0.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== +"@lerna/write-log-file@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-5.4.3.tgz" + integrity sha512-S2kctFhsO4mMbR52tW9VjYrGWUMYO5YIjprg8B7vQSwYvWOOJfqOKy/A+P/U5zXuCSAbDDGssyS+CCM36MFEQw== dependencies: - npmlog "^4.1.2" - write-file-atomic "^3.0.3" + npmlog "^6.0.2" + write-file-atomic "^4.0.1" -"@lumino/algorithm@^1.3.3", "@lumino/algorithm@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@lumino/algorithm/-/algorithm-1.6.0.tgz#771e7896cd94e660f9b58a52f80e1bb255de1d41" - integrity sha512-NMOcm5Yr9nXz5gokS/K4jHBbUMQYBkvDXl1n51XWdcz0LY+oGuIKPhjazhUgmbNRehzdZBj5hMMd1+htYWeVKQ== +"@lezer/common@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz" + integrity sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA== -"@lumino/application@^1.16.0": - version "1.20.0" - resolved "https://registry.yarnpkg.com/@lumino/application/-/application-1.20.0.tgz#b50ca4180bc400589fdfcfcaab08c4af937fccd0" - integrity sha512-FAoQcq4L3ZswTK0lWfLKnG1ecG26cwqjzg2fyoBeuWGBi1TG9BYjFBdV7ErTFMxW8jE1CLOLuxsZaKFLNErcKA== +"@lezer/cpp@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.0.0.tgz" + integrity sha512-Klk3/AIEKoptmm6cNm7xTulNXjdTKkD+hVOEcz/NeRg8tIestP5hsGHJeFDR/XtyDTxsjoPjKZRIGohht7zbKw== dependencies: - "@lumino/commands" "^1.15.0" - "@lumino/coreutils" "^1.8.0" - "@lumino/widgets" "^1.23.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" -"@lumino/collections@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@lumino/collections/-/collections-1.6.0.tgz#7d3e94cee26409b0cd719c1934bdda471e6a5662" - integrity sha512-ZETm0/xF0oUHV03sOXNOfFI1EEpS317HvN5n+fZBJvCNZIrJkWmKD8QuxcfwHb7AChKUhXlVHhDbWlb1LKnd7g== +"@lezer/css@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz" + integrity sha512-616VqgDKumHmYIuxs3tnX1irEQmoDHgF/TlP4O5ICWwyHwLMErq+8iKVuzTkOdBqvYAVmObqThcDEAaaMJjAdg== dependencies: - "@lumino/algorithm" "^1.6.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" -"@lumino/commands@^1.12.0", "@lumino/commands@^1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@lumino/commands/-/commands-1.15.0.tgz#06eb94fb4b34cad59f35b1fcaf473e8d2047f779" - integrity sha512-JOE68KfbR9xw5YTfcwo+9E0PSWidifEMAcOC/aXd7iSzfsCRknMTcMQIUGL277IU7J7CJvoe10DUE5QKwTmX+g== - dependencies: - "@lumino/algorithm" "^1.6.0" - "@lumino/coreutils" "^1.8.0" - "@lumino/disposable" "^1.7.0" - "@lumino/domutils" "^1.5.0" - "@lumino/keyboard" "^1.5.0" - "@lumino/signaling" "^1.7.0" - "@lumino/virtualdom" "^1.11.0" - -"@lumino/coreutils@^1.5.3", "@lumino/coreutils@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@lumino/coreutils/-/coreutils-1.8.0.tgz#4feb3ccbfbc3efc8e395a90f22b5a938fbad959a" - integrity sha512-OvCsaASUqOE7R6Dxngyk4/b5QMOjyRUNxuZuuL+fx+JvGKZFZ/B2c9LYtAJ9mDmQ1BQiGNV/qSpL4o7x8PCfjw== - -"@lumino/datagrid@^0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@lumino/datagrid/-/datagrid-0.20.0.tgz#ef7f7a987d6a99a9ca559d4a24544793dd2e843d" - integrity sha512-4zUKlfU7F0rKp2grBagTTAfIFui1NM2tTu2wPyA2hCOx7HROc2tYmi1MfZHCPzr/mtg+LspBpd4DSvEOkeR7AA== - dependencies: - "@lumino/algorithm" "^1.3.3" - "@lumino/coreutils" "^1.5.3" - "@lumino/disposable" "^1.4.3" - "@lumino/domutils" "^1.2.3" - "@lumino/dragdrop" "^1.7.1" - "@lumino/keyboard" "^1.2.3" - "@lumino/messaging" "^1.4.3" - "@lumino/signaling" "^1.4.3" - "@lumino/widgets" "^1.19.0" - -"@lumino/disposable@^1.4.3", "@lumino/disposable@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@lumino/disposable/-/disposable-1.7.0.tgz#539463490cb42e8d2dc46b5ff7cc291f4f1a8d07" - integrity sha512-3mWi11ko3XVY63BPwvys7MXrbFddA2i+gp72d0wAKM2NDDUopVPikMHhJpjGJcw+otjahzXYiTewxPDEau9dYg== +"@lezer/generator@^1.0.0": + version "1.1.1" + resolved "https://registry.npmjs.org/@lezer/generator/-/generator-1.1.1.tgz" + integrity sha512-GrB5EwOn09yf5YfDk6TcspHcF7PQZP83665moY5VmOURwCmNOx+Qit3mwp7W/EsGpqd4PPRioxNkYwYZii69cw== dependencies: - "@lumino/algorithm" "^1.6.0" - "@lumino/signaling" "^1.7.0" + "@lezer/common" "^1.0.0" + "@lezer/lr" "^1.0.0" -"@lumino/domutils@^1.2.3", "@lumino/domutils@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@lumino/domutils/-/domutils-1.5.0.tgz#fdba0cfe404b4817e63aa064f63b3c965655e76e" - integrity sha512-dZ0Aa+/qhvfPc1aa5kX4LLGE3B6BW1XmJa0R1XVCEpAFY3cZiujuQWmhYHJtZPrOiqn0UtioT2OpqnWdtCWc0A== +"@lezer/highlight@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz" + integrity sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA== + dependencies: + "@lezer/common" "^1.0.0" -"@lumino/dragdrop@^1.10.0", "@lumino/dragdrop@^1.7.1": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@lumino/dragdrop/-/dragdrop-1.10.0.tgz#2fddacfee055e660dd33dd9a3cfbd8fbba811673" - integrity sha512-A3cNLcp09zygOprWmLTkLZCQYNq3dJfN+mhni4IZizqCTkKbTCEzo2/IwoCWvy+ABKft8d/A9Y40wFW6yJ9OyA== +"@lezer/html@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@lezer/html/-/html-1.0.1.tgz" + integrity sha512-sC00zEt3GBh3vVO6QaGX4YZCl41S9dHWN/WGBsDixy9G+sqOC7gsa4cxA/fmRVAiBvhqYkJk+5Ul4oul92CPVw== + dependencies: + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/java@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/java/-/java-1.0.0.tgz" + integrity sha512-z2EA0JHq2WoiKfQy5uOOd4t17PJtq8guh58gPkSzOnNcQ7DNbkrU+Axak+jL8+Noinwyz2tRNOseQFj+Tg+P0A== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/javascript@^1.0.0": + version "1.0.2" + resolved "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz" + integrity sha512-IjOVeIRhM8IuafWNnk+UzRz7p4/JSOKBNINLYLsdSGuJS9Ju7vFdc82AlTt0jgtV5D8eBZf4g0vK4d3ttBNz7A== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/json@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz" + integrity sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/lr@^1.0.0": + version "1.2.1" + resolved "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.1.tgz" + integrity sha512-RpHRs+Q+5tPsXtobSfSeRFRAnTRD0e4bApDvo74O+JiaWq9812x5S8WgftNX67owdaTQXCB5E8XZGALo4Wt77A== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/markdown@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.1.tgz" + integrity sha512-LlpNWLqes3XQvd8TwpJTHf9ENl4fI6H32xQkMgltUITFMMdQpOASXQtDawWR03yS6hskh4bkhATQbgjdGMoUvA== + dependencies: + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + +"@lezer/php@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/php/-/php-1.0.0.tgz" + integrity sha512-kFQu/mk/vmjpA+fjQU87d9eimqKJ9PFCa8CZCPFWGEwNnm7Ahpw32N+HYEU/YAQ0XcfmOAnW/YJCEa8WpUOMMw== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/python@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@lezer/python/-/python-1.1.0.tgz" + integrity sha512-FVPp2usfj3zZuc+2RidXAY94WAcsHQ3dbKDbXuZgoAwUungAcXwd3EWXiWQvwNqbae+ek51bWi8dwbiQqweWCg== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/rust@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.0.tgz" + integrity sha512-IpGAxIjNxYmX9ra6GfQTSPegdCAWNeq23WNmrsMMQI7YNSvKtYxO4TX5rgZUmbhEucWn0KTBMeDEPXg99YKtTA== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/xml@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.0.tgz" + integrity sha512-73iI9UK8iqSvWtLlOEl/g+50ivwQn8Ge6foHVN66AXUS1RccFnAoc7BYU8b3c8/rP6dfCOGqAGaWLxBzhj60MA== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lumino/algorithm@^1.9.1": + version "1.9.1" + resolved "https://registry.npmjs.org/@lumino/algorithm/-/algorithm-1.9.1.tgz" + integrity sha512-d0rj7IYRzYj6WbWSrbJbKvrfO4H0NUnXT2yjSWS/sCklpTpSp0IGmndK/X4r6gG+ev5lb5+wBg9ofUDBvoAlAw== + +"@lumino/application@^1.29.0": + version "1.29.2" + resolved "https://registry.npmjs.org/@lumino/application/-/application-1.29.2.tgz" + integrity sha512-Ub8NNaWqYTrM8fdJt4+GKaAMjCO4OYHmO/aOBX1uzOqj/ZXHm3d8hFxmrfcijrRbTdiTZkVEZ8zyJorNDJZSEg== + dependencies: + "@lumino/commands" "^1.20.0" + "@lumino/coreutils" "^1.12.0" + "@lumino/widgets" "^1.33.0" + +"@lumino/collections@^1.9.1": + version "1.9.1" + resolved "https://registry.npmjs.org/@lumino/collections/-/collections-1.9.1.tgz" + integrity sha512-5RaRGUY7BJ/1j173sc9DCfiVf70Z0hopRnBV8/AeAaK9bJJRAYjDhlZ9O8xTyouegh6krkOfiDyjl3pwogLrQw== + dependencies: + "@lumino/algorithm" "^1.9.1" + +"@lumino/commands@^1.20.0": + version "1.20.0" + resolved "https://registry.npmjs.org/@lumino/commands/-/commands-1.20.0.tgz" + integrity sha512-xyrzDIJ9QEbcbRAwmXrjb7A7/E5MDNbnLANKwqmFVNF+4LSnF62obdvY4On3Rify3HmfX0u16Xr9gfoWPX9wLQ== + dependencies: + "@lumino/algorithm" "^1.9.1" + "@lumino/coreutils" "^1.12.0" + "@lumino/disposable" "^1.10.1" + "@lumino/domutils" "^1.8.1" + "@lumino/keyboard" "^1.8.1" + "@lumino/signaling" "^1.10.1" + "@lumino/virtualdom" "^1.14.1" + +"@lumino/coreutils@^1.12.0": + version "1.12.0" + resolved "https://registry.npmjs.org/@lumino/coreutils/-/coreutils-1.12.0.tgz" + integrity sha512-DSglh4ylmLi820CNx9soJmDJCpUgymckdWeGWuN0Ash5g60oQvrQDfosVxEhzmNvtvXv45WZEqSBzDP6E5SEmQ== + +"@lumino/datagrid@^0.36.0": + version "0.36.2" + resolved "https://registry.npmjs.org/@lumino/datagrid/-/datagrid-0.36.2.tgz" + integrity sha512-988G5rQjrKQAjqHJpibAkURO94TkljiRtikW1ObkI7nljP/uYFim4zd0jaZWdTjFNJ9cB038QWfofArsV+4/AA== + dependencies: + "@lumino/algorithm" "^1.9.1" + "@lumino/coreutils" "^1.12.0" + "@lumino/disposable" "^1.10.1" + "@lumino/domutils" "^1.8.1" + "@lumino/dragdrop" "^1.14.0" + "@lumino/keyboard" "^1.8.1" + "@lumino/messaging" "^1.10.1" + "@lumino/signaling" "^1.10.1" + "@lumino/widgets" "^1.33.0" + +"@lumino/disposable@^1.10.1": + version "1.10.1" + resolved "https://registry.npmjs.org/@lumino/disposable/-/disposable-1.10.1.tgz" + integrity sha512-mZQILc8sVGZC7mJNOGVmehDRO9/u3sIRdjZ+pCYjDgXKcINLd6HoPhZDquKCWiRBfHTL1B3tOHjnBhahBc2N/Q== + dependencies: + "@lumino/algorithm" "^1.9.1" + "@lumino/signaling" "^1.10.1" + +"@lumino/domutils@^1.8.1": + version "1.8.1" + resolved "https://registry.npmjs.org/@lumino/domutils/-/domutils-1.8.1.tgz" + integrity sha512-QUVXwmDMIfcHC3yslhmyGK4HYBKaJ3xX5MTwDrjsSX7J7AZ4jwL4zfsxyF9ntdqEKraoJhLQ6BaUBY+Ur1cnYw== + +"@lumino/dragdrop@^1.14.0": + version "1.14.0" + resolved "https://registry.npmjs.org/@lumino/dragdrop/-/dragdrop-1.14.0.tgz" + integrity sha512-hO8sgF0BkpihKIP6UZgVJgiOEhz89i7Oxtp9FR9Jqw5alGocxSXt7q3cteMvqpcL6o2/s3CafZNRkVLRXmepNw== dependencies: - "@lumino/coreutils" "^1.8.0" - "@lumino/disposable" "^1.7.0" + "@lumino/coreutils" "^1.12.0" + "@lumino/disposable" "^1.10.1" -"@lumino/keyboard@^1.2.3", "@lumino/keyboard@^1.5.0", "@lumino/keyboard@^1.8.1": +"@lumino/keyboard@^1.8.1": version "1.8.1" - resolved "https://registry.yarnpkg.com/@lumino/keyboard/-/keyboard-1.8.1.tgz#e7850e2fb973fbb4c6e737ca8d9307f2dc3eb74b" + resolved "https://registry.npmjs.org/@lumino/keyboard/-/keyboard-1.8.1.tgz" integrity sha512-8x0y2ZQtEvOsblpI2gfTgf+gboftusP+5aukKEsgNQtzFl28RezQXEOSVd8iD3K6+Q1MaPQF0OALYP0ASqBjBg== -"@lumino/messaging@^1.4.3", "@lumino/messaging@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@lumino/messaging/-/messaging-1.7.0.tgz#32542f9e9a266fd5b3f71842f70cfe141e016d93" - integrity sha512-QYWf9QGIGD0Oes104zw7mVln4S8yRije2mZhNNRBjkYcDuQlPW+eRSuC5LwAMsFnGymBlUPwPbKOUEO2RbhAtg== +"@lumino/messaging@^1.10.1": + version "1.10.1" + resolved "https://registry.npmjs.org/@lumino/messaging/-/messaging-1.10.1.tgz" + integrity sha512-XZSdt9ih94rdeeLL0cryUw6HHD51D7TP8c+MFf+YRF6VKwOFB9RoajfQWadeqpmH+schTs3EsrFfA9KHduzC7w== dependencies: - "@lumino/algorithm" "^1.6.0" - "@lumino/collections" "^1.6.0" + "@lumino/algorithm" "^1.9.1" + "@lumino/collections" "^1.9.1" -"@lumino/polling@^1.3.3": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@lumino/polling/-/polling-1.6.0.tgz#64f40bba4602fe9eceb9f3fae8f3647831e5b7e9" - integrity sha512-jG1nqw6UO5XEN7QamOr6iDW8WvYeZQcBVRjM38fszz62dwJ/VGPvO2hlNl6QWWIfCynbJudms0LQm+z0BT1EdA== +"@lumino/polling@^1.10.0": + version "1.11.0" + resolved "https://registry.npmjs.org/@lumino/polling/-/polling-1.11.0.tgz" + integrity sha512-wXV9OXOLjsragDeeVg1fUIq48chLgKk7/VoxlydIWqs0T7sZS59u7InMUi0od0L+7URtDUHAQ9XfWYEFVs6mvQ== dependencies: - "@lumino/coreutils" "^1.8.0" - "@lumino/disposable" "^1.7.0" - "@lumino/signaling" "^1.7.0" + "@lumino/coreutils" "^1.12.0" + "@lumino/disposable" "^1.10.1" + "@lumino/signaling" "^1.10.1" -"@lumino/properties@^1.2.3", "@lumino/properties@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@lumino/properties/-/properties-1.5.0.tgz#7e8638e84c51bb110c5a69f91ca8b0e40b2c3fca" - integrity sha512-YqpJE6/1Wkjrie0E+ypu+yzd55B5RlvKYMnQs3Ox+SrJsnNBhA6Oj44EhVf8SUTuHgn1t/mm+LvbswKN5RM4+g== +"@lumino/properties@^1.8.1": + version "1.8.1" + resolved "https://registry.npmjs.org/@lumino/properties/-/properties-1.8.1.tgz" + integrity sha512-O+CCcAqP64Di32DUZ4Jqq0DtUyE5RJREN5vbkgGZGu+WauJ/RYoiLDe1ubbAeSaHk71OrS60ZBV7QyC8ZaBVsA== -"@lumino/signaling@^1.4.3", "@lumino/signaling@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@lumino/signaling/-/signaling-1.7.0.tgz#76da4738bf8f19e7da6de1d457a54220e2140670" - integrity sha512-a5kd11Sf04jTfpzxCr7TOBD2o5YvItA4IGwiOoG+QR6sPR0Rwmcf47fPItqXo5st58iNIblC3F+c264N+Me+gg== +"@lumino/signaling@^1.10.1": + version "1.10.1" + resolved "https://registry.npmjs.org/@lumino/signaling/-/signaling-1.10.1.tgz" + integrity sha512-GZVbX4cfk/ZqLwkemPD/NwqToaTL/6q7qdLpEhgkiPlaH1S5/V7fDpP7N1uFy4n3BDITId8cpYgH/Ds32Mdp3A== dependencies: - "@lumino/algorithm" "^1.6.0" + "@lumino/algorithm" "^1.9.1" -"@lumino/virtualdom@^1.11.0", "@lumino/virtualdom@^1.8.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@lumino/virtualdom/-/virtualdom-1.11.0.tgz#468b4d28a07e2b8988dc583b4aab40e37dc6955e" - integrity sha512-G0sIx4pLYbgJ4w+SIgsCYQgKP/GBrWgjh8wcumD6XpaYZNivJv4c01xITYYlh7FU61jZmMWMrxtZztArNRDSqg== - dependencies: - "@lumino/algorithm" "^1.6.0" - -"@lumino/widgets@^1.19.0", "@lumino/widgets@^1.23.0": - version "1.23.0" - resolved "https://registry.yarnpkg.com/@lumino/widgets/-/widgets-1.23.0.tgz#096c7574de75fa67b32bcb914c5dae290fbee6f3" - integrity sha512-0Akt9ESgc06SJ3EJG3VK1Liw+AAjRWkKMfm8VUTwT/1QJYYGZ8kfHNO97mkBLv+0EkLEkZIeaQb8fIoU6vh7bw== - dependencies: - "@lumino/algorithm" "^1.6.0" - "@lumino/commands" "^1.15.0" - "@lumino/coreutils" "^1.8.0" - "@lumino/disposable" "^1.7.0" - "@lumino/domutils" "^1.5.0" - "@lumino/dragdrop" "^1.10.0" - "@lumino/keyboard" "^1.5.0" - "@lumino/messaging" "^1.7.0" - "@lumino/properties" "^1.5.0" - "@lumino/signaling" "^1.7.0" - "@lumino/virtualdom" "^1.11.0" +"@lumino/virtualdom@^1.14.1": + version "1.14.1" + resolved "https://registry.npmjs.org/@lumino/virtualdom/-/virtualdom-1.14.1.tgz" + integrity sha512-imIJd/wtRkoR1onEiG5nxPEaIrf70nn4PgD/56ri3/Lo6AJEX2CusF6iIA27GVB8yl/7CxgTHUnzzCwTFPypcA== + dependencies: + "@lumino/algorithm" "^1.9.1" + +"@lumino/widgets@^1.33.0": + version "1.33.0" + resolved "https://registry.npmjs.org/@lumino/widgets/-/widgets-1.33.0.tgz" + integrity sha512-Kt1zYU0FOZLTcyCAPkCAqFhK6PW+VAB0WIFuGdihO8BblfhY7KRsPn041PwVTXHAZrid1yaB2/aN+HbB2zh4Nw== + dependencies: + "@lumino/algorithm" "^1.9.1" + "@lumino/commands" "^1.20.0" + "@lumino/coreutils" "^1.12.0" + "@lumino/disposable" "^1.10.1" + "@lumino/domutils" "^1.8.1" + "@lumino/dragdrop" "^1.14.0" + "@lumino/keyboard" "^1.8.1" + "@lumino/messaging" "^1.10.1" + "@lumino/properties" "^1.8.1" + "@lumino/signaling" "^1.10.1" + "@lumino/virtualdom" "^1.14.1" "@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== + version "1.0.9" + resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== dependencies: - detect-libc "^1.0.3" + detect-libc "^2.0.0" https-proxy-agent "^5.0.0" make-dir "^3.1.0" - node-fetch "^2.6.1" + node-fetch "^2.6.7" nopt "^5.0.0" - npmlog "^4.1.2" + npmlog "^5.0.1" 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" + semver "^7.3.5" + tar "^6.1.11" "@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" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -2272,291 +2381,357 @@ "@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" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" 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" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" 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/arborist@5.3.0": + version "5.3.0" + resolved "https://registry.npmjs.org/@npmcli/arborist/-/arborist-5.3.0.tgz" + integrity sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A== + dependencies: + "@isaacs/string-locale-compare" "^1.1.0" + "@npmcli/installed-package-contents" "^1.0.7" + "@npmcli/map-workspaces" "^2.0.3" + "@npmcli/metavuln-calculator" "^3.0.1" + "@npmcli/move-file" "^2.0.0" + "@npmcli/name-from-folder" "^1.0.1" + "@npmcli/node-gyp" "^2.0.0" + "@npmcli/package-json" "^2.0.0" + "@npmcli/run-script" "^4.1.3" + bin-links "^3.0.0" + cacache "^16.0.6" + common-ancestor-path "^1.0.1" + json-parse-even-better-errors "^2.3.1" + json-stringify-nice "^1.1.4" + mkdirp "^1.0.4" + mkdirp-infer-owner "^2.0.0" + nopt "^5.0.0" + npm-install-checks "^5.0.0" + npm-package-arg "^9.0.0" + npm-pick-manifest "^7.0.0" + npm-registry-fetch "^13.0.0" + npmlog "^6.0.2" + pacote "^13.6.1" + parse-conflict-json "^2.0.1" + proc-log "^2.0.0" + promise-all-reject-late "^1.0.0" + promise-call-limit "^1.0.1" + read-package-json-fast "^2.0.2" + readdir-scoped-modules "^1.1.0" + rimraf "^3.0.2" + semver "^7.3.7" + ssri "^9.0.0" + treeverse "^2.0.0" + walk-up-path "^1.0.0" "@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== + version "1.1.1" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== 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== +"@npmcli/fs@^2.1.0": + version "2.1.2" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz" + integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ== dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" + "@gar/promisify" "^1.1.3" + semver "^7.3.5" + +"@npmcli/git@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz" + integrity sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w== + dependencies: + "@npmcli/promise-spawn" "^3.0.0" + lru-cache "^7.4.4" mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" + npm-pick-manifest "^7.0.0" + proc-log "^2.0.0" 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": +"@npmcli/installed-package-contents@^1.0.7": version "1.0.7" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" + resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== dependencies: npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" +"@npmcli/map-workspaces@^2.0.3": + version "2.0.4" + resolved "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz" + integrity sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg== + dependencies: + "@npmcli/name-from-folder" "^1.0.1" + glob "^8.0.1" + minimatch "^5.0.1" + read-package-json-fast "^2.0.3" + +"@npmcli/metavuln-calculator@^3.0.1": + version "3.1.1" + resolved "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz" + integrity sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA== + dependencies: + cacache "^16.0.0" + json-parse-even-better-errors "^2.3.1" + pacote "^13.0.3" + semver "^7.3.5" + "@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" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz" 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/move-file@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz" + integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@npmcli/name-from-folder@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz" + integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== -"@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== +"@npmcli/node-gyp@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz" + integrity sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A== + +"@npmcli/package-json@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@npmcli/package-json/-/package-json-2.0.0.tgz" + integrity sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA== + dependencies: + json-parse-even-better-errors "^2.3.1" + +"@npmcli/promise-spawn@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz" + integrity sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g== 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== +"@npmcli/run-script@^4.1.0", "@npmcli/run-script@^4.1.3", "@npmcli/run-script@^4.1.7": + version "4.2.1" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz" + integrity sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg== + dependencies: + "@npmcli/node-gyp" "^2.0.0" + "@npmcli/promise-spawn" "^3.0.0" + node-gyp "^9.0.0" + read-package-json-fast "^2.0.3" + which "^2.0.2" + +"@nrwl/cli@14.5.6": + version "14.5.6" + resolved "https://registry.npmjs.org/@nrwl/cli/-/cli-14.5.6.tgz" + integrity sha512-twTR2nzA8xtTQHgMOUxNCXutRQ4OWT9eeJID3H6C5Ev5Mhi25fZheodVOQu72MpMWHhdtH7/7kHzULJaRsTjHw== + dependencies: + nx "14.5.6" + +"@nrwl/tao@14.5.6": + version "14.5.6" + resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-14.5.6.tgz" + integrity sha512-EIbYLhSU85SaYd95t3Mwcy09KVPyPd3DlE7sZBaS3TzFEgOi0o9DLrpHRiZWfUJYgY9ltZHPCQn2hKpd7h7auw== 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" + nx "14.5.6" "@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" + resolved "https://registry.npmjs.org/@nteract/transform-vdom/-/transform-vdom-4.0.16-alpha.0.tgz" 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== +"@octokit/auth-token@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.1.tgz" + integrity sha512-/USkK4cioY209wXRpund6HZzHo9GmjakpV9ycOkpMcMxMk7QVcVFVyCMtzvXYiHsB2crgDgrtNYSELYFBXhhaA== dependencies: - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" -"@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" +"@octokit/core@^4.0.0": + version "4.0.5" + resolved "https://registry.npmjs.org/@octokit/core/-/core-4.0.5.tgz" + integrity sha512-4R3HeHTYVHCfzSAi0C6pbGXV8UDI5Rk+k3G7kLVNckswN9mvpOzW9oENfjfH3nEmzg8y3AmKmzs8Sg6pLCeOCA== + 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" "^7.0.0" 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== +"@octokit/endpoint@^7.0.0": + version "7.0.1" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.1.tgz" + integrity sha512-/wTXAJwt0HzJ2IeE4kQXO+mBScfzyCkI0hMtkIaqyXd9zg76OpOfNQfHL9FlaxAV2RsNiOXZibVWloy8EexENg== dependencies: - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" 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== +"@octokit/graphql@^5.0.0": + version "5.0.1" + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.1.tgz" + integrity sha512-sxmnewSwAixkP1TrLdE6yRG53eEhHhDTYUykUwdV9x8f91WcbhunIHk9x1PZLALdBZKRPUO2HRcm4kezZ79HoA== dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" + "@octokit/request" "^6.0.0" + "@octokit/types" "^7.0.0" 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/openapi-types@^13.1.0": + version "13.1.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-13.1.0.tgz" + integrity sha512-Z7vzLqfTkoVQyoy/2iQla1N2I4Vav2wi4JbZK8QxIYAfBimhuflosFxmsqw5LTH7DkdNW46ZYpAcqJf0XaS8SQ== "@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" + resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz" 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== +"@octokit/plugin-paginate-rest@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.0.0.tgz" + integrity sha512-g4GJMt/7VDmIMMdQenN6bmsmRoZca1c7IxOdF2yMiMwQYrE2bmmypGQeQSD5rsaffsFMCUS7Br4pMVZamareYA== dependencies: - "@octokit/types" "^6.26.0" + "@octokit/types" "^7.0.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" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz" 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== +"@octokit/plugin-rest-endpoint-methods@^6.0.0": + version "6.3.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.3.0.tgz" + integrity sha512-qEu2wn6E7hqluZwIEUnDxWROvKjov3zMIAi4H4d7cmKWNMeBprEXZzJe8pE5eStUYC1ysGhD0B7L6IeG1Rfb+g== dependencies: - "@octokit/types" "^6.26.0" + "@octokit/types" "^7.0.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== +"@octokit/request-error@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.1.tgz" + integrity sha512-ym4Bp0HTP7F3VFssV88WD1ZyCIRoE8H35pXSKwLeMizcdZAYc/t6N9X9Yr9n6t3aG9IH75XDnZ6UeZph0vHMWQ== dependencies: - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" 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== +"@octokit/request@^6.0.0": + version "6.2.1" + resolved "https://registry.npmjs.org/@octokit/request/-/request-6.2.1.tgz" + integrity sha512-gYKRCia3cpajRzDSU+3pt1q2OcuC6PK8PmFIyxZDWCzRXRSIBH8jXjFJ8ZceoygBIm0KsEUg4x1+XcYBz7dHPQ== dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" + "@octokit/endpoint" "^7.0.0" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^7.0.0" is-plain-object "^5.0.0" - node-fetch "^2.6.1" + node-fetch "^2.6.7" 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== +"@octokit/rest@^19.0.3": + version "19.0.4" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.4.tgz" + integrity sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA== dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.0" + "@octokit/core" "^4.0.0" + "@octokit/plugin-paginate-rest" "^4.0.0" "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.9.0" + "@octokit/plugin-rest-endpoint-methods" "^6.0.0" + +"@octokit/types@^7.0.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-7.1.0.tgz" + integrity sha512-+ClA0jRc9zGFj5mfQeQNfgTlelzhpAexbAueQG1t2Xn8yhgnsjkF8bgLcUUpwrpqkv296uXyiGwkqXRSU7KYzQ== + dependencies: + "@octokit/openapi-types" "^13.1.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== +"@parcel/watcher@2.0.4": + version "2.0.4" + resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz" + integrity sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg== dependencies: - "@octokit/openapi-types" "^10.0.0" + node-addon-api "^3.2.1" + node-gyp-build "^4.3.0" "@phosphor/coreutils@^1.0.0": version "1.3.1" - resolved "https://registry.yarnpkg.com/@phosphor/coreutils/-/coreutils-1.3.1.tgz#441e34f42340f7faa742a88b2a181947a88d7226" + resolved "https://registry.npmjs.org/@phosphor/coreutils/-/coreutils-1.3.1.tgz" integrity sha512-9OHCn8LYRcPU/sbHm5v7viCA16Uev3gbdkwqoQqlV+EiauDHl70jmeL7XVDXdigl66Dz0LI11C99XOxp+s3zOA== -"@playwright/test@^1.16.2": - version "1.16.2" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.16.2.tgz#3eda8633e3f8fa33eac16225aab295e5e5d41a5a" - integrity sha512-nZVSGZ3XZxsFKt5TRYUgePsMLDBS8p2E6DPDd/dpICVxzPhBowsBd9IKSlq91faH4BE6nYMDjAfVAmqXLjohkA== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/core" "^7.14.8" - "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-dynamic-import" "^7.14.5" - "@babel/plugin-proposal-export-namespace-from" "^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-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-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-transform-modules-commonjs" "^7.14.5" - "@babel/preset-typescript" "^7.14.5" - colors "^1.4.0" - commander "^8.2.0" - debug "^4.1.1" - expect "=27.2.5" - jest-matcher-utils "=27.2.5" - jpeg-js "^0.4.2" - minimatch "^3.0.3" - ms "^2.1.2" - open "^8.3.0" - pirates "^4.0.1" - pixelmatch "^5.2.1" - playwright-core "=1.16.2" - pngjs "^5.0.0" - rimraf "^3.0.2" - source-map-support "^0.4.18" - stack-utils "^2.0.3" - -"@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== +"@playwright/test@^1.17.0": + version "1.24.2" + resolved "https://registry.npmjs.org/@playwright/test/-/test-1.24.2.tgz" + integrity sha512-Q4X224pRHw4Dtkk5PoNJplZCokLNvVbXD9wDQEMrHcEuvWpJWEQDeJ9gEwkZ3iCWSFSWBshIX177B231XW4wOQ== dependencies: - create-react-context "0.3.0" - invariant "^2.2.3" - prop-types "^15.6.1" - react-lifecycles-compat "^3.0.4" + "@types/node" "*" + playwright-core "1.24.2" + +"@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz" + integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== "@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== + version "3.2.1" + resolved "https://registry.npmjs.org/@rjsf/core/-/core-3.2.1.tgz" + integrity sha512-dk8ihvxFbcuIwU7G+HiJbFgwyIvaumPt5g5zfnuC26mwTUPlaDGFXKK2yITp8tJ3+hcwS5zEXtAN9wUkfuM4jA== 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" + jsonpointer "^5.0.0" 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== +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== "@sinonjs/commons@^1.7.0": version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz" 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" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz" 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" + resolved "https://registry.npmjs.org/@stdlib/array/-/array-0.0.12.tgz" integrity sha512-nDksiuvRC1dSTHrf5yOGQmlRwAzSKV8MdFQwFSvLbZGGhi5Y4hExqea5HloLgNVouVs8lnAFi2oubSM4Mc7YAg== dependencies: "@stdlib/assert" "^0.0.x" @@ -2570,7 +2745,7 @@ "@stdlib/assert@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/assert/-/assert-0.0.12.tgz#1648c9016e5041291f55a6464abcc4069c5103ce" + resolved "https://registry.npmjs.org/@stdlib/assert/-/assert-0.0.12.tgz" integrity sha512-38FxFf+ZoQZbdc+m09UsWtaCmzd/2e7im0JOaaFYE7icmRfm+4KiE9BRvBT4tIn7ioLB2f9PsBicKjIsf+tY1w== dependencies: "@stdlib/array" "^0.0.x" @@ -2592,14 +2767,14 @@ "@stdlib/bigint@^0.0.x": version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/bigint/-/bigint-0.0.11.tgz#c416a1d727001c55f4897e6424124199d638f2fd" + resolved "https://registry.npmjs.org/@stdlib/bigint/-/bigint-0.0.11.tgz" 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" + resolved "https://registry.npmjs.org/@stdlib/blas/-/blas-0.0.12.tgz" integrity sha512-nWY749bWceuoWQ7gz977blCwR7lyQ/rsIXVO4b600h+NFpeA2i/ea7MYC680utIbeu2cnDWHdglBPoK535VAzA== dependencies: "@stdlib/array" "^0.0.x" @@ -2611,7 +2786,7 @@ "@stdlib/buffer@^0.0.x": version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/buffer/-/buffer-0.0.11.tgz#6137b00845e6c905181cc7ebfae9f7e47c01b0ce" + resolved "https://registry.npmjs.org/@stdlib/buffer/-/buffer-0.0.11.tgz" integrity sha512-Jeie5eDDa1tVuRcuU+cBXI/oOXSmMxUUccZpqXzgYe0IO8QSNtNxv9mUTzJk/m5wH+lmLoDvNxzPpOH9TODjJg== dependencies: "@stdlib/array" "^0.0.x" @@ -2622,7 +2797,7 @@ "@stdlib/cli@^0.0.x": version "0.0.10" - resolved "https://registry.yarnpkg.com/@stdlib/cli/-/cli-0.0.10.tgz#28e2fbe6865d7f5cd15b7dc5846c99bd3b91674f" + resolved "https://registry.npmjs.org/@stdlib/cli/-/cli-0.0.10.tgz" integrity sha512-OITGaxG46kwK799+NuOd/+ccosJ9koVuQBC610DDJv0ZJf8mD7sbjGXrmue9C4EOh8MP7Vm/6HN14BojX8oTCg== dependencies: "@stdlib/utils" "^0.0.x" @@ -2630,7 +2805,7 @@ "@stdlib/complex@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/complex/-/complex-0.0.12.tgz#3afbc190cd0a9b37fc7c6e508c3aa9fda9106944" + resolved "https://registry.npmjs.org/@stdlib/complex/-/complex-0.0.12.tgz" integrity sha512-UbZBdaUxT2G+lsTIrVlRZwx2IRY6GXnVILggeejsIVxHSuK+oTyapfetcAv0FJFLP+Rrr+ZzrN4b9G3hBw6NHA== dependencies: "@stdlib/array" "^0.0.x" @@ -2640,7 +2815,7 @@ "@stdlib/constants@^0.0.x": version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/constants/-/constants-0.0.11.tgz#78cd56d6c2982b30264843c3d75bde7125e90cd2" + resolved "https://registry.npmjs.org/@stdlib/constants/-/constants-0.0.11.tgz" integrity sha512-cWKy0L9hXHUQTvFzdPkTvZnn/5Pjv7H4UwY0WC1rLt+A5CxFDJKjvnIi9ypSzJS3CAiGl1ZaHCdadoqXhNdkUg== dependencies: "@stdlib/array" "^0.0.x" @@ -2650,7 +2825,7 @@ "@stdlib/fs@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/fs/-/fs-0.0.12.tgz#662365fd5846a51f075724b4f2888ae88441b70d" + resolved "https://registry.npmjs.org/@stdlib/fs/-/fs-0.0.12.tgz" integrity sha512-zcDLbt39EEM3M3wJW6luChS53B8T+TMJkjs2526UpKJ71O0/0adR57cI7PfCpkMd33d05uM7GM+leEj4eks4Cw== dependencies: "@stdlib/array" "^0.0.x" @@ -2664,7 +2839,7 @@ "@stdlib/math@^0.0.x": version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/math/-/math-0.0.11.tgz#eb6638bc03a20fbd6727dd5b977ee0170bda4649" + resolved "https://registry.npmjs.org/@stdlib/math/-/math-0.0.11.tgz" integrity sha512-qI78sR1QqGjHj8k/aAqkZ51Su2fyBvaR/jMKQqcB/ML8bpYpf+QGlGvTty5Qdru/wpqds4kVFOVbWGcNFIV2+Q== dependencies: "@stdlib/assert" "^0.0.x" @@ -2679,7 +2854,7 @@ "@stdlib/ndarray@^0.0.x": version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/ndarray/-/ndarray-0.0.13.tgz#2e8fc645e10f56a645a0ab81598808c0e8f43b82" + resolved "https://registry.npmjs.org/@stdlib/ndarray/-/ndarray-0.0.13.tgz" integrity sha512-Z+U9KJP4U2HWrLtuAXSPvhNetAdqaNLMcliR6S/fz+VPlFDeymRK7omRFMgVQ+1zcAvIgKZGJxpLC3vjiPUYEw== dependencies: "@stdlib/array" "^0.0.x" @@ -2696,7 +2871,7 @@ "@stdlib/nlp@^0.0.x": version "0.0.11" - resolved "https://registry.yarnpkg.com/@stdlib/nlp/-/nlp-0.0.11.tgz#532ec0f7267b8d639e4c20c6de864e8de8a09054" + resolved "https://registry.npmjs.org/@stdlib/nlp/-/nlp-0.0.11.tgz" integrity sha512-D9avYWANm0Db2W7RpzdSdi5GxRYALGAqUrNnRnnKIO6sMEfr/DvONoAbWruda4QyvSC+0MJNwcEn7+PHhRwYhw== dependencies: "@stdlib/array" "^0.0.x" @@ -2708,7 +2883,7 @@ "@stdlib/number@^0.0.x": version "0.0.10" - resolved "https://registry.yarnpkg.com/@stdlib/number/-/number-0.0.10.tgz#4030ad8fc3fac19a9afb415c443cee6deea0e65c" + resolved "https://registry.npmjs.org/@stdlib/number/-/number-0.0.10.tgz" integrity sha512-RyfoP9MlnX4kccvg8qv7vYQPbLdzfS1Mnp/prGOoWhvMG3pyBwFAan34kwFb5IS/zHC3W5EmrgXCV2QWyLg/Kg== dependencies: "@stdlib/array" "^0.0.x" @@ -2722,7 +2897,7 @@ "@stdlib/os@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/os/-/os-0.0.12.tgz#08bbf013c62a7153099fa9cbac086ca1349a4677" + resolved "https://registry.npmjs.org/@stdlib/os/-/os-0.0.12.tgz" integrity sha512-O7lklZ/9XEzoCmYvzjPh7jrFWkbpOSHGI71ve3dkSvBy5tyiSL3TtivfKsIC+9ZxuEJZ3d3lIjc9e+yz4HVbqQ== dependencies: "@stdlib/assert" "^0.0.x" @@ -2733,7 +2908,7 @@ "@stdlib/process@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/process/-/process-0.0.12.tgz#123325079d89a32f4212f72fb694f8fe3614cf18" + resolved "https://registry.npmjs.org/@stdlib/process/-/process-0.0.12.tgz" integrity sha512-P0X0TMvkissBE1Wr877Avi2/AxmP7X5Toa6GatHbpJdDg6jQmN4SgPd+NZNp98YtZUyk478c8XSIzMr1krQ20g== dependencies: "@stdlib/assert" "^0.0.x" @@ -2746,7 +2921,7 @@ "@stdlib/random@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/random/-/random-0.0.12.tgz#e819c3abd602ed5559ba800dba751e49c633ff85" + resolved "https://registry.npmjs.org/@stdlib/random/-/random-0.0.12.tgz" integrity sha512-c5yND4Ahnm9Jx0I+jsKhn4Yrz10D53ALSrIe3PG1qIz3kNFcIPnmvCuNGd+3V4ch4Mbrez55Y8z/ZC5RJh4vJQ== dependencies: "@stdlib/array" "^0.0.x" @@ -2768,15 +2943,15 @@ "@stdlib/regexp@^0.0.x": version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/regexp/-/regexp-0.0.13.tgz#80b98361dc7a441b47bc3fa964bb0c826759e971" + resolved "https://registry.npmjs.org/@stdlib/regexp/-/regexp-0.0.13.tgz" 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": +"@stdlib/stats@^0.0.x", "@stdlib/stats@~0.0.13": version "0.0.13" - resolved "https://registry.yarnpkg.com/@stdlib/stats/-/stats-0.0.13.tgz#87c973f385379d794707c7b5196a173dba8b07e1" + resolved "https://registry.npmjs.org/@stdlib/stats/-/stats-0.0.13.tgz" integrity sha512-hm+t32dKbx/L7+7WlQ1o4NDEzV0J4QSnwFBCsIMIAO8+VPxTZ4FxyNERl4oKlS3hZZe4AVKjoOVhBDtgEWrS4g== dependencies: "@stdlib/array" "^0.0.x" @@ -2793,7 +2968,7 @@ "@stdlib/streams@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/streams/-/streams-0.0.12.tgz#07f5ceae5852590afad8e1cb7ce94174becc8739" + resolved "https://registry.npmjs.org/@stdlib/streams/-/streams-0.0.12.tgz" integrity sha512-YLUlXwjJNknHp92IkJUdvn5jEQjDckpawKhDLLCoxyh3h5V+w/8+61SH7TMTfKx5lBxKJ8vvtchZh90mIJOAjQ== dependencies: "@stdlib/assert" "^0.0.x" @@ -2807,7 +2982,7 @@ "@stdlib/strided@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/strided/-/strided-0.0.12.tgz#86ac48e660cb7f64a45cf07e80cbbfe58be21ae1" + resolved "https://registry.npmjs.org/@stdlib/strided/-/strided-0.0.12.tgz" integrity sha512-1NINP+Y7IJht34iri/bYLY7TVxrip51f6Z3qWxGHUCH33kvk5H5QqV+RsmFEGbbyoGtdeHrT2O+xA+7R2e3SNg== dependencies: "@stdlib/assert" "^0.0.x" @@ -2817,9 +2992,9 @@ "@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== + version "0.0.14" + resolved "https://registry.npmjs.org/@stdlib/string/-/string-0.0.14.tgz" + integrity sha512-1ClvUTPysens7GZz3WsrkFYIFs8qDmnXkyAd3zMvTXgRpy7hqrv6nNzLMQj8BHv5cBWaWPOXYd/cZ+JyMnZNQQ== dependencies: "@stdlib/assert" "^0.0.x" "@stdlib/cli" "^0.0.x" @@ -2835,7 +3010,7 @@ "@stdlib/symbol@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/symbol/-/symbol-0.0.12.tgz#b9f396b0bf269c2985bb7fe99810a8e26d7288c3" + resolved "https://registry.npmjs.org/@stdlib/symbol/-/symbol-0.0.12.tgz" integrity sha512-2IDhpzWVGeLHgsvIsX12RXvf78r7xBkc4QLoRUv3k7Cp61BisR1Ym1p0Tq9PbxT8fknlvLToh9n5RpmESi2d4w== dependencies: "@stdlib/assert" "^0.0.x" @@ -2843,7 +3018,7 @@ "@stdlib/time@^0.0.x": version "0.0.14" - resolved "https://registry.yarnpkg.com/@stdlib/time/-/time-0.0.14.tgz#ea6daa438b1d3b019b99f5091117ee4bcef55d60" + resolved "https://registry.npmjs.org/@stdlib/time/-/time-0.0.14.tgz" integrity sha512-1gMFCQTabMVIgww+k4g8HHHIhyy1tIlvwT8mC0BHW7Q7TzDAgobwL0bvor+lwvCb5LlDAvNQEpaRgVT99QWGeQ== dependencies: "@stdlib/assert" "^0.0.x" @@ -2855,13 +3030,13 @@ "@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== + version "0.0.14" + resolved "https://registry.npmjs.org/@stdlib/types/-/types-0.0.14.tgz" + integrity sha512-AP3EI9/il/xkwUazcoY+SbjtxHRrheXgSbWZdEGD+rWpEgj6n2i63hp6hTOpAB5NipE0tJwinQlDGOuQ1lCaCw== "@stdlib/utils@^0.0.x": version "0.0.12" - resolved "https://registry.yarnpkg.com/@stdlib/utils/-/utils-0.0.12.tgz#670de5a7b253f04f11a4cba38f790e82393bcb46" + resolved "https://registry.npmjs.org/@stdlib/utils/-/utils-0.0.12.tgz" integrity sha512-+JhFpl6l7RSq/xGnbWRQ5dAL90h9ONj8MViqlb7teBZFtePZLMwoRA1wssypFcJ8SFMRWQn7lPmpYVUkGwRSOg== dependencies: "@stdlib/array" "^0.0.x" @@ -2883,500 +3058,32 @@ "@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== +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== dependencies: - defer-to-connect "^1.0.1" + defer-to-connect "^2.0.0" "@tootallnate/once@1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + "@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== + version "7.1.19" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -3385,643 +3092,585 @@ "@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== + version "7.6.4" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== 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" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" 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== + version "7.17.1" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz" + integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== 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" + resolved "https://registry.npmjs.org/@types/base16/-/base16-1.0.2.tgz" 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/cacheable-request@^6.0.1": + version "6.0.2" + resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz" + integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "*" + "@types/node" "*" + "@types/responselike" "*" "@types/clone@~2.1.1": version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/clone/-/clone-2.1.1.tgz#9b880d0ce9b1f209b5e0bd6d9caa38209db34024" + resolved "https://registry.npmjs.org/@types/clone/-/clone-2.1.1.tgz" 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== +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== 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== + version "8.4.5" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz" + integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^0.0.50": +"@types/estree@*": + version "1.0.0" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@^0.0.50": version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== +"@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + "@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== + version "9.0.13" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz" + integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== 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== +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== 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" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" 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/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-cache-semantics@*": + version "4.0.1" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz" + integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== "@types/inquirer@^7.3.1": version "7.3.3" - resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.3.tgz#92e6676efb67fa6925c69a2ee638f67a822952ac" + resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz" 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/is-glob@^4.0.1": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/is-glob/-/is-glob-4.0.2.tgz" + integrity sha512-4j5G9Y5jljDSICQ1R2f/Rcyoj6DZmYGneny+p/cDkjep0rkqNg0W73Ty0bVjMUTZgLXHf8oiMjg1XC3CDwCz+g== "@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== + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== "@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" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" 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" + resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz" 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/json-buffer@~3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz" + integrity sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ== + +"@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/json5@^0.0.30": version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz" 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== +"@types/keyv@*": + version "3.1.4" + resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: - "@types/lodash" "*" + "@types/node" "*" "@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== + version "4.0.7" + resolved "https://registry.npmjs.org/@types/lodash.escape/-/lodash.escape-4.0.7.tgz" + integrity sha512-k6BN7TWKe5rO11yIhMsVh2K9IZ0h9Vfw168/D/+Bv39qCz7vk0WIKTo8OORsah9o1vlDlkUoieAiU8AuYhXpwQ== 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/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== +"@types/lodash.mergewith@^4.6.1": + version "4.6.7" + resolved "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz" + integrity sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A== dependencies: - "@types/react" "*" + "@types/lodash" "*" -"@types/marked@^1.1.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/marked/-/marked-1.2.2.tgz#1f858a0e690247ecf3b2eef576f98f86e8d960d4" - integrity sha512-wLfw1hnuuDYrFz97IzJja0pdVsC0oedtS4QsKH1/inyW9qkLQbXgMUqEQT0MVtUBx3twjWeInUfjQbhBVLECXw== +"@types/lodash@*", "@types/lodash@^4.14.178": + version "4.14.182" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== -"@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/marked@^4.0.3": + version "4.0.3" + resolved "https://registry.npmjs.org/@types/marked/-/marked-4.0.3.tgz" + integrity sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg== "@types/minimatch@*", "@types/minimatch@^3.0.3": version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz" 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" + resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@types/mkdirp@^0.5.2": + version "0.5.2" + resolved "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz" + integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg== + dependencies: + "@types/node" "*" + "@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== + version "2.6.2" + resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== 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/node@*": + version "18.6.3" + resolved "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz" + integrity sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg== + +"@types/node@^14.6.1": + version "14.18.23" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.23.tgz" + integrity sha512-MhbCWN18R4GhO8ewQWAFK4TGQdBpXWByukz7cWyJmXhvRuCIaM/oWytGPqVmDzgEnnaIc9ss6HbU5mUi+vyZPA== "@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" + resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz" 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" + resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" 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/prettier@^1.16.1": + version "1.19.1" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz" + integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== -"@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/prettier@^2.0.0", "@types/prettier@~2.6.0": + version "2.6.4" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz" + integrity sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw== -"@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/prop-types@*", "@types/prop-types@^15.7.4": + version "15.7.5" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== "@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== + version "17.0.17" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz" + integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== dependencies: - "@types/react" "*" + "@types/react" "^17" "@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== + version "0.3.5" + resolved "https://registry.npmjs.org/@types/react-highlighter/-/react-highlighter-0.3.5.tgz" + integrity sha512-65qPJI8Teofk9bWx9FeLBcG5rH7YjkUdgySo7SGyQHaM16snlIJL3exFqAmUpLBAOqpf1lNRpefYOsCGCfKsVQ== 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" + resolved "https://registry.npmjs.org/@types/react-paginate/-/react-paginate-6.2.3.tgz" 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== +"@types/react@*", "@types/react@^17", "@types/react@^17.0.0": + version "17.0.48" + resolved "https://registry.npmjs.org/@types/react/-/react-17.0.48.tgz" + integrity sha512-zJ6IYlJ8cYYxiJfUaZOQee4lh99mFihBoqkOSEGV+dFi9leROW6+PgstzQ+w3gWTnUfskALtQPGHK6dYmPj+2A== 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== +"@types/responselike@*", "@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== dependencies: - "@types/react" "*" + "@types/node" "*" "@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== + version "2.6.2" + resolved "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.6.2.tgz" + integrity sha512-7Lu2zMQnmHHQGKXVvCOhSziQMpa+R2hMHFefzbYoYMHeaXR0uXqNeOc3JeQQQ8/6Xa2Br/P1IQTLzV09xxAiUQ== dependencies: htmlparser2 "^6.0.0" "@types/scheduler@*": version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" 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== + version "7.3.10" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.10.tgz" + integrity sha512-zsv3fsC7S84NN6nPK06u79oWgrPVd0NvOyqgghV1haPaFcVxIrP4DLomRwGAXk0ui4HZA7mOcSFL98sMVW9viw== "@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" + resolved "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz" 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" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" 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" + resolved "https://registry.npmjs.org/@types/supports-color/-/supports-color-5.3.0.tgz" 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" + resolved "https://registry.npmjs.org/@types/text-encoding/-/text-encoding-0.0.35.tgz" 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" + resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz" 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== + version "1.4.8" + resolved "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz" + integrity sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw== -"@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-env@^1.14.1": + version "1.17.0" + resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.17.0.tgz" + integrity sha512-eHSaNYEyxRA5IAG0Ym/yCyf86niZUIF/TpWKofQI/CVfh5HsMEUyfE2kwFxha4ow0s5g0LfISQxpDKjbRDrizw== -"@types/webpack-sources@*", "@types/webpack-sources@^0.1.5": +"@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" + resolved "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.9.tgz" 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== + version "7.4.7" + resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== 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== + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^15.0.0": version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz" integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== dependencies: "@types/yargs-parser" "*" -"@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - -"@types/yauzl@^2.9.1": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" - integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== - dependencies: - "@types/node" "*" - -"@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== +"@typescript-eslint/eslint-plugin@~5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.28.0.tgz" + integrity sha512-DXVU6Cg29H2M6EybqSg2A+x8DgO9TCUBRp4QEXQHJceLS7ogVDP0g3Lkg/SZCqcvkAP/RruuQqK0gdlkgmhSUA== dependencies: - "@typescript-eslint/experimental-utils" "4.8.2" - "@typescript-eslint/scope-manager" "4.8.2" - debug "^4.1.1" + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/type-utils" "5.28.0" + "@typescript-eslint/utils" "5.28.0" + debug "^4.3.4" 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" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@~5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.28.0.tgz" + integrity sha512-ekqoNRNK1lAcKhZESN/PdpVsWbP9jtiNqzFWkp/yAUdZvJalw2heCYuqRmM5eUJSIYEkgq5sGOjq+ZqsLMjtRA== + dependencies: + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/typescript-estree" "5.28.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.28.0.tgz" + integrity sha512-LeBLTqF/he1Z+boRhSqnso6YrzcKMTQ8bO/YKEe+6+O/JGof9M0g3IJlIsqfrK/6K03MlFIlycbf1uQR1IjE+w== + dependencies: + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/visitor-keys" "5.28.0" + +"@typescript-eslint/scope-manager@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz" + integrity sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg== + dependencies: + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" + +"@typescript-eslint/type-utils@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.28.0.tgz" + integrity sha512-SyKjKh4CXPglueyC6ceAFytjYWMoPHMswPQae236zqe1YbhvCVQyIawesYywGiu98L9DwrxsBN69vGIVxJ4mQQ== + dependencies: + "@typescript-eslint/utils" "5.28.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.28.0.tgz" + integrity sha512-2OOm8ZTOQxqkPbf+DAo8oc16sDlVR5owgJfKheBkxBKg1vAfw2JsSofH9+16VPlN9PWtv8Wzhklkqw3k/zCVxA== + +"@typescript-eslint/types@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz" + integrity sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ== + +"@typescript-eslint/typescript-estree@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.28.0.tgz" + integrity sha512-9GX+GfpV+F4hdTtYc6OV9ZkyYilGXPmQpm6AThInpBmKJEyRSIjORJd1G9+bknb7OTFYL+Vd4FBJAO6T78OVqA== + dependencies: + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/visitor-keys" "5.28.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz" + integrity sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg== + dependencies: + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.28.0.tgz" + integrity sha512-E60N5L0fjv7iPJV3UGc4EC+A3Lcj4jle9zzR0gW7vXhflO7/J29kwiTGITA2RlrmPokKiZbBy2DgaclCaEUs6g== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.28.0" + "@typescript-eslint/types" "5.28.0" + "@typescript-eslint/typescript-estree" "5.28.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" -"@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== +"@typescript-eslint/utils@^5.10.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz" + integrity sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ== 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== + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/typescript-estree" "5.32.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" -"@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== +"@typescript-eslint/visitor-keys@5.28.0": + version "5.28.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz" + integrity sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA== 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/types" "5.28.0" + eslint-visitor-keys "^3.3.0" -"@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== +"@typescript-eslint/visitor-keys@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz" + integrity sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g== dependencies: - "@typescript-eslint/types" "4.8.2" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "5.32.0" + eslint-visitor-keys "^3.3.0" -"@verdaccio/commons-api@10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@verdaccio/commons-api/-/commons-api-10.0.0.tgz#2d7de8722f94181f1a71891fe91198a7c14e6dea" - integrity sha512-UC8wrRI9FvqjfDeB1RijF7aVI0JJhCOI8RkEDibCT/JD8zVngphrNmgSWcjo8Es3lRiu7NugWXDSuggCCeCfUg== +"@verdaccio/commons-api@10.2.0": + version "10.2.0" + resolved "https://registry.npmjs.org/@verdaccio/commons-api/-/commons-api-10.2.0.tgz" + integrity sha512-F/YZANu4DmpcEV0jronzI7v2fGVWkQ5Mwi+bVmV+ACJ+EzR0c9Jbhtbe5QyLUuzR97t8R5E/Xe53O0cc2LukdQ== dependencies: - http-errors "1.8.0" - http-status-codes "1.4.0" + http-errors "2.0.0" + http-status-codes "2.2.0" -"@verdaccio/file-locking@10.0.0", "@verdaccio/file-locking@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@verdaccio/file-locking/-/file-locking-10.0.0.tgz#3d476a6ba28207c795d49828438e7335166c1cfc" - integrity sha512-2tQUbJF3tQ3CY9grAlpovaF/zu8G56CBYMaeHwMBHo9rAmsJI9i7LfliHGS6Jygbs8vd0cOCPT7vl2CL9T8upw== +"@verdaccio/file-locking@10.3.0": + version "10.3.0" + resolved "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-10.3.0.tgz" + integrity sha512-FE5D5H4wy/nhgR/d2J5e1Na9kScj2wMjlLPBHz7XF4XZAVSRdm45+kL3ZmrfA6b2HTADP/uH7H05/cnAYW8bhw== dependencies: lockfile "1.0.4" -"@verdaccio/local-storage@10.0.6": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@verdaccio/local-storage/-/local-storage-10.0.6.tgz#be485a8107ad84206cf80702d325ca47b7f22f68" - integrity sha512-YEImOMUL56lziS/N3o1YzoOcVGZXpyZclGSonw7XQ1lKQEvEhU06V2+tIdjPgtqIOuH9ZKdPeBsBuN7ILa2qzQ== - dependencies: - "@verdaccio/commons-api" "10.0.0" - "@verdaccio/file-locking" "10.0.0" - "@verdaccio/streams" "10.0.0" - async "3.2.0" - debug "4.3.1" +"@verdaccio/local-storage@10.3.1": + version "10.3.1" + resolved "https://registry.npmjs.org/@verdaccio/local-storage/-/local-storage-10.3.1.tgz" + 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/readme@10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@verdaccio/readme/-/readme-10.0.0.tgz#f9627c32b309ace311318b98b2c42226823f6cd7" - integrity sha512-OD3dMnRC8SvhgytEzczMBleN+K/3lMqyWw/epeXvolCpCd7mW/Dl5zSR25GiHh/2h3eTKP/HMs4km8gS1MMLgA== +"@verdaccio/readme@10.4.1": + version "10.4.1" + resolved "https://registry.npmjs.org/@verdaccio/readme/-/readme-10.4.1.tgz" + integrity sha512-OZ6R+HF2bIU3WFFdPxgUgyglaIfZzGSqyUfM2m1TFNfDCK84qJvRIgQJ1HG/82KVOpGuz/nxVyw2ZyEZDkP1vA== dependencies: - dompurify "^2.2.6" - jsdom "15.2.1" - marked "^2.0.1" + dompurify "2.3.9" + jsdom "16.7.0" + marked "4.0.18" -"@verdaccio/streams@10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@verdaccio/streams/-/streams-10.0.0.tgz#8b06e1d6f06e906ebda0f1d4089cdb651a533541" - integrity sha512-PqxxY11HhweN6z1lwfn9ydLCdnOkCPpthMZs+SGCDz8Rt6gOyrjJVslV7o4uobDipjD9+hUPpJHDeO33Qt24uw== +"@verdaccio/streams@10.2.0": + version "10.2.0" + resolved "https://registry.npmjs.org/@verdaccio/streams/-/streams-10.2.0.tgz" + integrity sha512-FaIzCnDg0x0Js5kSQn1Le3YzDHl7XxrJ0QdIw5LrDUmLsH3VXNi4/NMlSHnw5RiTTMs4UbEf98V3RJRB8exqJA== -"@verdaccio/ui-theme@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@verdaccio/ui-theme/-/ui-theme-3.1.0.tgz#21108f3c1b97e6db5901509d935e1f4ce475950a" - integrity sha512-NmJOcv25/OtF84YrmYxi31beFde7rt+/y2qlnq0wYR4ZCFRE5TsuqisTVTe1OyJ8D8JwwPMyMSMSMtlMwUfqIQ== +"@verdaccio/ui-theme@6.0.0-6-next.25": + version "6.0.0-6-next.25" + resolved "https://registry.npmjs.org/@verdaccio/ui-theme/-/ui-theme-6.0.0-6-next.25.tgz" + integrity sha512-zN+72MBsRLzpAzH7NWLQlWEM3k+L+k2Mt08foySELQtN+a2UFHlqkJWDnX7mQNcOiml8eV+ukPUt7wQNn+ziXw== "@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== + version "1.56.1" + resolved "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.56.1.tgz" + integrity sha512-dbARd50EaQKvXMmuVxZw3Ztp8yK+k852zt96FmGwp272MWQWApZzuQdb/5viTD4BzQRGXRgkCvkuiRsonem0Yg== "@webassemblyjs/ast@1.11.1": version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz" 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/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz" integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== dependencies: "@webassemblyjs/floating-point-hex-parser" "1.11.1" @@ -4030,17 +3679,12 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz" integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== dependencies: "@webassemblyjs/ast" "1.11.1" @@ -4048,57 +3692,28 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz" 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" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz" integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== dependencies: "@webassemblyjs/ast" "1.11.1" @@ -4110,23 +3725,9 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz" integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== dependencies: "@webassemblyjs/ast" "1.11.1" @@ -4135,20 +3736,9 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz" integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== dependencies: "@webassemblyjs/ast" "1.11.1" @@ -4156,19 +3746,9 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz" integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== dependencies: "@webassemblyjs/ast" "1.11.1" @@ -4178,115 +3758,76 @@ "@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" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz" 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/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== -"@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== +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== 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" +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== "@xtuc/ieee754@^1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" 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" + resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" 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" + resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz" 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" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" 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.0, 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== +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abstract-leveldown@^6.2.1, abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +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== @@ -4297,81 +3838,68 @@ abstract-leveldown@^6.2.1, abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: 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" - -acorn-globals@^4.3.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== +accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" + 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" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz" integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== dependencies: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.3.1: +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - acorn-walk@^7.1.1: version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^6.0.1, 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-walk@^8.0.0: + version "8.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.1.1: version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" 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== +acorn@^8.0.4, acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== 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== + resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz" + integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== 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" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" 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== +agentkeepalive@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz" + integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== dependencies: debug "^4.1.0" depd "^1.1.2" @@ -4379,48 +3907,20 @@ agentkeepalive@^4.1.3: aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" 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: +ajv-keywords@^3.5.2: version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -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: +ajv@^6.10.0, 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" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -4428,444 +3928,280 @@ 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 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== +ajv@^8.0.1: + version "8.11.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== 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== + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" 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== + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" -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: +ansi-regex@^2.1.1: 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= + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== 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== + version "4.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" 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: +ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 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" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -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" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== anymatch@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz" 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: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" -apache-md5@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/apache-md5/-/apache-md5-1.1.2.tgz#ee49736b639b4f108b6e9e626c6da99306b41692" - integrity sha1-7klza2ObTxCLbp5ibG2pkwa0FpI= - -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== +apache-md5@1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.7.tgz" + integrity sha512-JtHjzZmJxtzfTSjsCyHgPR155HBe5WGyUyHTaEkfy46qhwCFKx1Epm6nAxgUG3WfUZP1dWhGqj9Z2NOBeZ+uBw== -aproba@^2.0.0: +"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" 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== +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== dependencies: delegates "^1.0.0" - readable-stream "^2.0.6" + readable-stream "^3.6.0" argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" 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" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" 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= + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz" 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= + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz" + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== array-differ@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + resolved "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - 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" + resolved "https://registry.npmjs.org/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz" 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= + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== 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= + resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz" + integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -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== +array-includes@^3.1.4, array-includes@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" 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" + is-string "^1.0.7" array-union@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== -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== +array.prototype.flatmap@^1.2.5: + version "1.3.0" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz" + integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" -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== +array.prototype.reduce@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz" + integrity sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.19.2" es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.5" + is-string "^1.0.7" arrify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== arrify@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + resolved "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz" 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" + resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== 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== + version "0.2.6" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== 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" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== 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== + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -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.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== +async@3.2.4: + version "3.2.4" + resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz" + 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== + version "2.6.4" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== 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= + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 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" + resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== atob@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" 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" + resolved "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz" 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= + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== aws4@^1.8.0: version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz" 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" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz" integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: "@jest/transform" "^26.6.2" @@ -4878,57 +4214,36 @@ babel-jest@^26.6.3: 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== + version "8.2.5" + resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz" + integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.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" + resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz" integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== 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== + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== 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" + istanbul-lib-instrument "^5.0.4" 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" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz" integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== dependencies: "@babel/template" "^7.3.3" @@ -4936,196 +4251,33 @@ babel-plugin-jest-hoist@^26.6.2: "@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== +babel-plugin-polyfill-corejs2@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz" + integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q== dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.2" + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.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= +babel-plugin-polyfill-corejs3@^0.5.3: + version "0.5.3" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz" + integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw== 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/helper-define-polyfill-provider" "^0.3.2" + core-js-compat "^3.21.0" -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== +babel-plugin-polyfill-regenerator@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz" + integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw== 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/helper-define-polyfill-provider" "^0.3.2" 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" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -5143,59 +4295,35 @@ babel-preset-current-node-syntax@^1.0.0: 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" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz" 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" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +balanced-match@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz" + integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== + base16@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" - integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + resolved "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz" + integrity sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ== -base64-js@^1.0.2, base64-js@^1.3.1: +base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" 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" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz" integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" @@ -5208,136 +4336,103 @@ base@^0.11.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= + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz" + integrity sha512-CtGuTyWf3ig+sgRyC7uP6DM3N+5ur/p8L+FPfsd+BbIfIs74TFfCajZTHnCw6K5dqM0bZEbRIqRy1fAdiUJhTA== 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= + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== 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= + resolved "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz" + integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== 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" + resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz" 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" + resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" 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== +bin-links@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/bin-links/-/bin-links-3.0.2.tgz" + integrity sha512-+oSWBdbCUK6X4LOCSrU36fWRzZNaK7/evX7GozR9xwl2dyiVi3UOUwTyyOVYI1FstgugfsM9QESRrWo7gjCYbg== + dependencies: + cmd-shim "^5.0.0" + mkdirp-infer-owner "^2.0.0" + npm-normalize-package-bin "^1.0.0" + read-cmd-shim "^3.0.0" + rimraf "^3.0.0" + write-file-atomic "^4.0.0" binary-extensions@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" 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== +bl@^4.0.3, bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: - file-uri-to-path "1.0.0" + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.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== + resolved "https://registry.npmjs.org/blacklist/-/blacklist-1.1.4.tgz" + integrity sha512-DWdfwimA1WQxVC69Vs1Fy525NbYwisMSCdYQmW9zyzOByz9OB/tQwrKZ3T3pbTkuFjnkJFlJuyiDjPiXL5kzew== -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== +body-parser@1.20.0: + version "1.20.0" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz" + integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== dependencies: - bytes "3.1.0" + bytes "3.1.2" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" + on-finished "2.4.1" + qs "6.10.3" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" -boolbase@^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" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^2.3.1, braces@^2.3.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^2.3.1: version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" @@ -5351,228 +4446,90 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" 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" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" 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== +browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.21.3: + version "4.21.3" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== 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" + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" bs-logger@0.x: version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" 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" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - 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= + resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== 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" + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" ieee754 "^1.1.13" -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= + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz" + integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ== -byline@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" - integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= +builtins@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" byte-size@^7.0.0: version "7.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" + resolved "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz" 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== - -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" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== -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" +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^15.0.5, cacache@^15.2.0: +cacache@^15.0.5: version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== dependencies: "@npmcli/fs" "^1.0.0" @@ -5594,9 +4551,33 @@ cacache@^15.0.5, cacache@^15.2.0: tar "^6.0.2" unique-filename "^1.1.1" +cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: + version "16.1.2" + resolved "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz" + integrity sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA== + 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 "^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" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz" integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" @@ -5609,22 +4590,27 @@ cache-base@^1.0.1: 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== +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" http-cache-semantics "^4.0.0" - keyv "^3.0.0" + keyv "^4.0.0" lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" + normalize-url "^6.0.1" + responselike "^2.0.0" 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" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== dependencies: function-bind "^1.1.1" @@ -5632,44 +4618,17 @@ call-bind@^1.0.0, call-bind@^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= + resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz" + integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw== callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" 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: +camel-case@^4.1.1, camel-case@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz" integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== dependencies: pascal-case "^3.1.2" @@ -5677,168 +4636,93 @@ camel-case@^4.1.1: camelcase-keys@^6.2.2: version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz" 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" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" 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== +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -canonicalize@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.5.tgz#b43b390ce981d397908bb847c3a8d9614323a47b" - integrity sha512-mAjKJPIyP0xqqv6IAkvso07StOmz6cmGtNDg3pXCSzXVZOqka7StIkAhJl/zHOi4M2CgpYfD6aeRWbnrmtvBEA== +caniuse-lite@^1.0.30001370: + version "1.0.30001373" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz" + integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ== -canvas@^2.6.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.8.0.tgz#f99ca7f25e6e26686661ffa4fec1239bbef74461" - integrity sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q== +canvas@^2.9.1: + version "2.9.3" + resolved "https://registry.npmjs.org/canvas/-/canvas-2.9.3.tgz" + integrity sha512-WOUM7ghii5TV2rbhaZkh1youv/vW1/Canev6Yx6BG2W+1S07w8jKZqKkPnbiPpQEDsnJdN8ouDd7OvQEGXDcUw== dependencies: "@mapbox/node-pre-gyp" "^1.0.0" - nan "^2.14.0" + nan "^2.15.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" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" 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= + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" -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: +chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 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== +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" 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" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" 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" + resolved "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz" + integrity sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g== -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== +chokidar@^3.4.0, chokidar@^3.5.1: + version "3.5.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -5850,54 +4734,29 @@ chokidar@^3.3.0, chokidar@^3.4.0, chokidar@^3.4.1: 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" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz" 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" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz" 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" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" @@ -5905,98 +4764,69 @@ class-utils@^0.3.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.3: + version "4.2.4" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz" + integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== + dependencies: + source-map "~0.6.0" -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== +clean-css@^5.2.2: + version "5.3.1" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz" + integrity sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg== 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" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" 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= +cli-color@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz" + integrity sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w== dependencies: - restore-cursor "^2.0.0" + 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" -cli-cursor@^3.1.0: +cli-cursor@3.1.0, cli-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" 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-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" +cli-spinners@2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== -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-spinners@^2.5.0: + version "2.7.0" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz" + integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== cli-width@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -clipanion@3.0.0-rc.12: - version "3.0.0-rc.12" - resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-3.0.0-rc.12.tgz#8c235961feb4851c437fc4f23a4c4c1387622a4a" - integrity sha512-eCixNguza61+8MXXTu6sYzpA8gPZHZzvay4lpFFpr4KSy+43wsugdiKMNejLS9PVcnSuGf0fy9kYs5R2c7Ejmw== +clipanion@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/clipanion/-/clipanion-3.1.0.tgz" + integrity sha512-v025Hz+IDQ15FpOyK8p02h5bFznMu6rLFsJSyOPR+7WrbSnZ1Ek6pblPukV7K5tC/dsWfncQPIrJ4iUy2PXkbw== dependencies: typanion "^3.3.1" -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" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== dependencies: string-width "^4.2.0" @@ -6005,7 +4835,7 @@ cliui@^6.0.0: cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" @@ -6014,222 +4844,203 @@ cliui@^7.0.2: clone-deep@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== dependencies: is-plain-object "^2.0.4" kind-of "^6.0.2" shallow-clone "^3.0.0" +clone-regexp@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz" + integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q== + dependencies: + is-regexp "^2.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= + version "1.0.3" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== 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= + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== clone@~2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== -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== +cmd-shim@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-5.0.0.tgz" + integrity sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw== 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== + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== 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" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" 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= + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== dependencies: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0, color-convert@^1.9.1: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 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" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" 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= + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 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" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 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== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== 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== +color-support@^1.1.2, color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== dependencies: - color-convert "^1.9.1" - color-string "^1.5.4" + color-convert "^1.9.3" + color-string "^1.6.0" -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== +colord@^2.9.2: + version "2.9.2" + resolved "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz" + integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== -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== +colorette@^2.0.14: + version "2.0.19" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -columnify@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= +columnify@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz" + integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== dependencies: - strip-ansi "^3.0.0" + strip-ansi "^6.0.1" 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" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" 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: +commander@2, commander@^2.20.0: version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" 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@7, commander@^7.0.0, commander@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== commander@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" 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@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -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@^8.2.0: +commander@^8.3.0: version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -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@^9.4.0: + version "9.4.0" + resolved "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz" + integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw== commander@~6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.0.0.tgz#2b270da94f8fb9014455312f829a1129dbf8887e" + resolved "https://registry.npmjs.org/commander/-/commander-6.0.0.tgz" integrity sha512-s7EA+hDtTYNhuXkTlhqew4txMZVdszBmKWSPEMxGr8ru8JXR7bLUFIAtPhcSuFdJQ0ILMxnJi8GkQL0yvDy/YA== +common-ancestor-path@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz" + integrity sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w== + commondir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== compare-func@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + resolved "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz" integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== dependencies: array-ify "^1.0.0" dot-prop "^5.1.0" -compare-versions@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" - integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== - component-emitter@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compress-brotli@^1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz" + integrity sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ== + dependencies: + "@types/json-buffer" "~3.0.0" + json-buffer "~3.0.1" + compressible@~2.0.16: version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" 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" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" @@ -6242,7 +5053,7 @@ compression@1.7.4: compute-gcd@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/compute-gcd/-/compute-gcd-1.2.1.tgz#34d639f3825625e1357ce81f0e456a6249d8c77f" + resolved "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz" integrity sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg== dependencies: validate.io-array "^1.0.3" @@ -6251,7 +5062,7 @@ compute-gcd@^1.2.1: compute-lcm@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23" + resolved "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz" integrity sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ== dependencies: compute-gcd "^1.2.1" @@ -6261,22 +5072,12 @@ compute-lcm@^1.1.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" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz" integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== dependencies: buffer-from "^1.0.0" @@ -6286,63 +5087,41 @@ concat-stream@^2.0.0: config-chain@^1.1.12: version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz" 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== + proto-list "~1.2.1" -console-control-strings@^1.0.0, console-control-strings@~1.1.0: +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= + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -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== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: - safe-buffer "5.1.2" + 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" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" 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== + version "5.0.13" + resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz" + integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== 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== +conventional-changelog-core@^4.2.4: + version "4.2.4" + resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz" + integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== dependencies: add-stream "^1.0.0" conventional-changelog-writer "^5.0.0" @@ -6361,17 +5140,17 @@ conventional-changelog-core@^4.2.2: 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" + resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz" 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== + version "5.0.1" + resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz" + integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ== dependencies: conventional-commits-filter "^2.0.7" dateformat "^3.0.0" - handlebars "^4.7.6" + handlebars "^4.7.7" json-stringify-safe "^5.0.1" lodash "^4.17.15" meow "^8.0.0" @@ -6381,16 +5160,16 @@ conventional-changelog-writer@^5.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" + resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz" 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== + version "3.2.4" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz" + integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" @@ -6398,11 +5177,10 @@ conventional-commits-parser@^3.2.0: 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" + resolved "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz" integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== dependencies: concat-stream "^2.0.0" @@ -6414,63 +5192,39 @@ conventional-recommended-bump@^6.1.0: 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: +convert-source-map@^1.4.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" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" 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= + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -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.npmjs.org/cookie/-/cookie-0.5.0.tgz" + 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" + resolved "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz" 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" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== 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" + resolved "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz" integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== dependencies: cacache "^15.0.5" @@ -6485,32 +5239,32 @@ copy-webpack-plugin@^6.0.1: 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== +core-js-compat@^3.21.0, core-js-compat@^3.22.1: + version "3.24.1" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.1.tgz" + integrity sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.3" 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.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-js-pure@^3.6.5: + version "3.24.1" + resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.1.tgz" + integrity sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== cors@2.8.5: version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== dependencies: object-assign "^4" @@ -6518,34 +5272,13 @@ cors@2.8.5: 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" + resolved "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz" + integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ== -cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -6553,65 +5286,22 @@ cosmiconfig@^7.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" + resolved "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz" 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" +crelt@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz" + integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA== cross-spawn@^6.0.0: version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" @@ -6622,314 +5312,242 @@ cross-spawn@^6.0.0: 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" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" 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" + resolved "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz" 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-functions-list@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz" + integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== -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== +css-loader@^6.7.1: + version "6.7.1" + resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz" + integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== dependencies: icss-utils "^5.1.0" - loader-utils "^2.0.0" - postcss "^8.2.15" + postcss "^8.4.7" 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" + postcss-value-parser "^4.2.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== + version "4.3.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 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-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" -css-tree@^1.1.2: +css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz" 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== +css-what@^6.0.1: + version "6.1.0" + resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== cssesc@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csso@^4.0.2: +csso@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + resolved "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz" 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.1, cssom@^0.4.4: +cssom@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz" 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" +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.0.0, cssstyle@^2.3.0: +cssstyle@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" 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.10: + version "3.0.10" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== -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== +csstype@^3.0.10, csstype@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz" + integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== + +csstype@~3.0.3: + version "3.0.11" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== 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= + resolved "https://registry.npmjs.org/csv-spectrum/-/csv-spectrum-1.0.0.tgz" + integrity sha512-0jEBU/Vyly6QO54ha2iJqqBq9F2J3EbSQf8SJ0NqHk9Q0EUhIquda4MFLhqVQA/vAnzLBgR/0Twrf1sm+/F6Yw== -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 - 3", "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@^3.1.1: + version "3.2.0" + resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz" + integrity sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g== + dependencies: + internmap "1 - 2" -"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== +d3-array@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.1.1.tgz" + integrity sha512-33qQ+ZoZlli19IFiQx4QEpf2CBEayMRzhlisJHSCsSUbDXv6ZishqS1x7uFVClKG4Wr7rZVHvaAttoLow6GqdQ== dependencies: - internmap "^1.0.0" + internmap "1 - 2" -"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-color@1 - 3", d3-color@^3.0.1: + version "3.1.0" + resolved "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== -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== +d3-delaunay@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz" + integrity sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ== dependencies: - delaunator "4" + delaunator "5" -"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-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== -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== +d3-dsv@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz" + integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== dependencies: - commander "2" - iconv-lite "0.4" + commander "7" + iconv-lite "0.6" 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== +d3-force@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz" + integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== dependencies: - d3-dispatch "1 - 2" - d3-quadtree "1 - 2" - d3-timer "1 - 2" + d3-dispatch "1 - 3" + d3-quadtree "1 - 3" + d3-timer "1 - 3" -"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-format@1 - 3", d3-format@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== -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== +d3-geo-projection@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz" + integrity sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg== dependencies: - commander "2" - d3-array "1 - 2" - d3-geo "1.12.0 - 2" - resolve "^1.1.10" + commander "7" + d3-array "1 - 3" + d3-geo "1.12.0 - 3" -"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== +"d3-geo@1.12.0 - 3", d3-geo@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz" + integrity sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA== dependencies: - d3-array "^2.5.0" + d3-array "2.5.0 - 3" -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-hierarchy@^3.1.0: + version "3.1.2" + resolved "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz" + integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== -"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== +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== dependencies: - d3-color "1 - 2" + d3-color "1 - 3" -"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-path@1 - 3", d3-path@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz" + integrity sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w== -"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-quadtree@1 - 3": + version "3.0.1" + resolved "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz" + integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== -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== +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== 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-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" -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== +d3-shape@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz" + integrity sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ== dependencies: - d3-path "1 - 2" + d3-path "1 - 3" -"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== +"d3-time-format@2 - 4", d3-time-format@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== dependencies: - d3-time "1 - 2" + d3-time "1 - 3" -"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== +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz" + integrity sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ== dependencies: - d3-array "2" + d3-array "2 - 3" -"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== +"d3-timer@1 - 3", d3-timer@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== d@1, d@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== dependencies: es5-ext "^0.10.50" @@ -6937,28 +5555,19 @@ d@1, d@^1.0.1: dargs@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" + resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz" 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= + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== dependencies: assert-plus "^1.0.0" -data-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.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" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: abab "^2.0.3" @@ -6967,125 +5576,108 @@ data-urls@^2.0.0: dateformat@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dayjs@1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2" - integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw== +dayjs@1.11.3: + version "1.11.3" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz" + integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@^3.0.0, debug@^3.1.1: +debug@^3.1.1, debug@^3.2.7: version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" 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= + resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz" + integrity sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw== 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= + resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz" + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decimal.js@^10.2.1: version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz" 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" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz" + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== decompress-response@^4.2.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz" integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== dependencies: mimic-response "^2.0.0" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.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" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" 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== + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" 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= + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz" + integrity sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA== 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== +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== deferred-leveldown@~5.3.0: version "5.3.0" @@ -7097,289 +5689,186 @@ deferred-leveldown@~5.3.0: define-lazy-prop@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -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== +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== dependencies: - object-keys "^1.0.12" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" 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= + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz" + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== 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= + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== 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" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz" 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== +delaunator@5: + version "5.0.0" + resolved "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz" + integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw== + dependencies: + robust-predicates "^3.0.0" 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== + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -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= + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -depd@~2.0.0: +depd@2.0.0, depd@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + dependency-graph@^0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.9.0.tgz#11aed7e203bc8b00f48356d92db27b265c445318" + resolved "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz" 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" + resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz" 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.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== +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 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= + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz" + integrity sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g== detect-indent@^6.0.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz" 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-libc@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== 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" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" 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= + version "1.0.4" + resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz" + integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== 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" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== -diff-sequences@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" - integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== - -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" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" 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" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz" 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== + version "1.4.1" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== 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@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" + version "2.3.0" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== domexception@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz" 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" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz" 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== +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" -dompurify@^2.2.6: - version "2.3.0" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.0.tgz#07bb39515e491588e5756b1d3e8375b5964814e2" - integrity sha512-VV5C6Kr53YVHGOBKO/F86OYX6/iLTw2yVSI721gKetxpHCK/V5TaLEf9ODjRgl1KLSWRMY6cUhAbv/c+IUnwQw== - -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" +dompurify@2.3.9: + version "2.3.9" + resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.9.tgz" + integrity sha512-3zOnuTwup4lPV/GfGS6UzG4ub9nhSYagR/5tB3AvDEwqyy5dtyCM2dVjwGDCnrPerXifBKTYh/UWCGKK7ydhhw== -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== +domutils@^2.0.0, domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== dependencies: dom-serializer "^1.0.1" domelementtype "^2.2.0" @@ -7387,78 +5876,39 @@ domutils@^2.0.0, domutils@^2.5.2, domutils@^2.6.0: dot-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== dependencies: no-case "^3.0.4" tslib "^2.0.3" -dot-prop@^5.1.0, dot-prop@^5.2.0: +dot-prop@^5.1.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz" 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" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz" 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= +dotenv@~10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -duplexer@^0.1.1: +duplexer@^0.1.1, duplexer@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" 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" - 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" + resolved "https://registry.npmjs.org/duplicate-package-checker-webpack-plugin/-/duplicate-package-checker-webpack-plugin-3.0.0.tgz" integrity sha512-aO50/qPC7X2ChjRFniRiscxBLT/K01bALqfcDaf8Ih5OqQ1N4iT/Abx9Ofu3/ms446vHTm46FACIuJUmgUQcDQ== dependencies: chalk "^2.3.0" @@ -7468,99 +5918,48 @@ duplicate-package-checker-webpack-plugin@^3.0.0: 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= + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== 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" + resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" 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" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.202: + version "1.4.210" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.210.tgz" + integrity sha512-kSiX4tuyZijV7Cz0MWVmGT8K2siqaOA4Z66K5dCttPPRh0HicOcOAEj1KlC8O8J1aOS/1M8rGofOzksLKaHWcQ== emittery@^0.7.1: version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz" 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" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" 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" + resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" 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= + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== encoding-down@^6.3.0: version "6.3.0" @@ -7572,74 +5971,56 @@ encoding-down@^6.3.0: level-codec "^9.0.0" level-errors "^2.0.0" -encoding@^0.1.12: +encoding@^0.1.13: 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.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" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" 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== +enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0: + version "5.10.0" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz" + integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -enquirer@^2.3.5, enquirer@^2.3.6: +enquirer@~2.3.6: version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" 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" + resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" 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" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" 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" + resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" 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" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -errno@^0.1.3, errno@~0.1.1, errno@~0.1.7: +errno@~0.1.1: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== @@ -7648,60 +6029,60 @@ errno@^0.1.3, errno@~0.1.1, errno@~0.1.7: error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" 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== +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.1: + version "1.20.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" + function.prototype.name "^1.1.5" get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" 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" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" 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" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" 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" + resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz" 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.9.0: + version "0.9.3" + resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== -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-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" 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" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" @@ -7709,23 +6090,18 @@ es-to-primitive@^1.2.1: is-symbol "^1.0.2" es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + version "0.10.62" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== 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" + es6-symbol "^3.1.3" + next-tick "^1.1.0" -es6-iterator@^2.0.3, es6-iterator@~2.0.3: +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= + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== dependencies: d "1" es5-ext "^0.10.35" @@ -7733,33 +6109,20 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.3: es6-promise@~4.2.8: version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" 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: +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" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz" 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" - es6-weak-map@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz" integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== dependencies: d "1" @@ -7769,49 +6132,32 @@ es6-weak-map@^2.0.3: escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" 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= + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +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" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^1.11.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - escodegen@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz" integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== dependencies: esprima "^4.0.1" @@ -7821,231 +6167,201 @@ escodegen@^2.0.0: 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-config-prettier@~8.5.0: + version "8.5.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== -eslint-import-resolver-node@0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== +eslint-import-resolver-node@0.3.6: + version "0.3.6" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: - debug "^2.6.9" - resolve "^1.13.1" + debug "^3.2.7" + resolve "^1.20.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== +eslint-plugin-jest@~26.5.3: + version "26.5.3" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.5.3.tgz" + integrity sha512-sICclUqJQnR1bFRZGLN2jnSVsYOsmPYYnroGCIMVSvTS3y8XR3yjzy1EcTQmk6typ5pRgyIWzbjqxK6cZHEZuQ== dependencies: - "@typescript-eslint/experimental-utils" "^4.0.1" + "@typescript-eslint/utils" "^5.10.0" -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== +eslint-plugin-prettier@~4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== 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== +eslint-plugin-react@~7.29.4: + version "7.29.4" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" doctrine "^2.1.0" - has "^1.0.3" + estraverse "^5.3.0" 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" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" + prop-types "^15.8.1" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" -eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" 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== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" + esrecurse "^4.3.0" + estraverse "^5.2.0" -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== +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== 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" 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" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" 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== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@~8.17.0: + version "8.17.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz" + integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== dependencies: - "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.2.1" + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" 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" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.19" - minimatch "^3.0.4" + lodash.merge "^4.6.2" + minimatch "^3.1.2" 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" + regexpp "^3.2.0" + strip-ansi "^6.0.1" 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== +espree@^9.3.2: + version "9.3.3" + resolved "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz" + integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.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" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" 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: +esquery@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== dependencies: estraverse "^5.1.0" -esrecurse@^4.1.0, esrecurse@^4.3.0: +esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" 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" +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" 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= + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== event-emitter@^0.3.5: version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== dependencies: d "1" es5-ext "~0.10.14" eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0, events@^3.2.0: +events@^3.2.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" 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" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz" 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" + resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" @@ -8056,9 +6372,9 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^4.0.0, execa@^4.1.0: +execa@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: cross-spawn "^7.0.0" @@ -8073,7 +6389,7 @@ execa@^4.0.0, execa@^4.1.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -8086,15 +6402,22 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execall@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz" + integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow== + dependencies: + clone-regexp "^2.1.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= + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== 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= + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -8104,21 +6427,9 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@=27.2.5: - version "27.2.5" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.5.tgz#16154aaa60b4d9a5b0adacfea3e4d6178f4b93fd" - integrity sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA== - dependencies: - "@jest/types" "^27.2.5" - ansi-styles "^5.0.0" - jest-get-type "^27.0.6" - jest-matcher-utils "^27.2.5" - jest-message-util "^27.2.5" - jest-regex-util "^27.0.6" - expect@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + resolved "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz" integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: "@jest/types" "^26.6.2" @@ -8128,81 +6439,78 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" -express@4.17.1, 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== +express-rate-limit@5.5.1: + version "5.5.1" + resolved "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz" + integrity sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg== + +express@4.18.1: + version "4.18.1" + resolved "https://registry.npmjs.org/express/-/express-4.18.1.tgz" + integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== dependencies: - accepts "~1.3.7" + accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" + body-parser "1.20.0" + content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.4.0" + cookie "0.5.0" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.2" + depd "2.0.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "~1.1.2" + 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.3.0" + on-finished "2.4.1" parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" + proxy-addr "~2.0.7" + qs "6.10.3" 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" + 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" ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + version "1.6.0" + resolved "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== dependencies: - type "^2.0.0" + type "^2.5.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= + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== 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= + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== 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" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" 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" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" @@ -8211,7 +6519,7 @@ external-editor@^3.0.3: extglob@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz" integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" @@ -8223,47 +6531,29 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1, fast-deep-equal@~3.1.3: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, 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" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 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" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" 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: +fast-glob@3.2.7: version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz" integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -8272,143 +6562,79 @@ fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.4: 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-glob@^3.0.3, fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + 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-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-patch@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz" + integrity sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ== 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" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 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= + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 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== + version "3.1.1" + resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.1.tgz" + integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== -fast-safe-stringify@^2.0.7: - version "2.0.8" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f" - integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag== +fast-safe-stringify@2.1.1, fast-safe-stringify@^2.0.8: + version "2.1.1" + resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz" + 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== + version "1.0.16" + resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== 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== + version "1.13.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== 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" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== dependencies: bser "2.1.1" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - -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: +figures@3.2.0, figures@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" 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: +file-entry-cache@^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== + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" 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= + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -8417,169 +6643,94 @@ fill-range@^4.0.0: fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" 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.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" - on-finished "~2.3.0" + on-finished "2.4.1" parseurl "~1.3.3" - statuses "~1.5.0" + statuses "2.0.1" 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== + version "3.3.2" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== 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: +find-root@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" 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= + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== 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== +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: - locate-path "^6.0.0" + locate-path "^5.0.0" path-exists "^4.0.0" -find-versions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" - integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - semver-regex "^3.1.2" + flatted "^3.1.0" + rimraf "^3.0.2" -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" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== flatstr@^1.0.12: version "1.0.12" - resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" + resolved "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz" integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== -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" +flatted@^3.1.0: + version "3.2.6" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== 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== + version "1.15.1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== 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" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== 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" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== form-data@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz" integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" @@ -8588,62 +6739,57 @@ form-data@^3.0.0: form-data@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" 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= +format-util@^1.0.3: + version "1.0.5" + resolved "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== forwarded@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" 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= + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz" + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== 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" + resolved "https://registry.npmjs.org/free-style/-/free-style-3.1.0.tgz" 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= + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -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-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -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= +fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.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" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== dependencies: at-least-node "^1.0.0" @@ -8651,42 +6797,17 @@ fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.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" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.1.2, fsevents@~2.3.2: version "2.3.2" @@ -8695,137 +6816,150 @@ fsevents@^2.1.2, fsevents@~2.3.2: function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 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== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.0" 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= + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== 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== + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -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= +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== dependencies: - aproba "^1.0.3" + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + 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" 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" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" 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" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" 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== + version "1.1.2" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" - -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + has-symbols "^1.0.3" 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" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" 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== + version "4.2.1" + resolved "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz" + integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== dependencies: "@hutson/parse-repository-url" "^3.0.0" hosted-git-info "^4.0.0" - meow "^7.0.0" through2 "^2.0.0" + yargs "^16.2.0" get-port@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz" 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-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz" + integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^4.0.0, get-stream@^4.1.0: +get-stream@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" 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" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" 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" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + 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= + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== getpass@^0.1.1: version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== 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" + resolved "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-1.0.3.tgz" 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== + version "2.0.11" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz" + integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== dependencies: dargs "^7.0.0" lodash "^4.17.15" @@ -8835,93 +6969,77 @@ git-raw-commits@^2.0.8: 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= + resolved "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz" + integrity sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw== 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" + resolved "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz" 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== +git-up@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz" + integrity sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA== dependencies: - is-ssh "^1.3.0" - parse-url "^6.0.0" + is-ssh "^1.4.0" + parse-url "^7.0.2" -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== +git-url-parse@^12.0.0: + version "12.0.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz" + integrity sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q== dependencies: - git-up "^4.0.0" + git-up "^6.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= + resolved "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz" + integrity sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ== 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: +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" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" 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== +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 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= + is-glob "^4.0.3" 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" + resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@7.1.4: + version "7.1.4" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + 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" + glob@^6.0.1: version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= + resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz" + integrity sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A== dependencies: inflight "^1.0.4" inherits "2" @@ -8929,9 +7047,32 @@ glob@^6.0.1: 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: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.0.1, glob@^8.0.3: + version "8.0.3" + resolved "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz" + integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +glob@~7.1.6: version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" @@ -8941,59 +7082,37 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, gl 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: +global-modules@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" 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== +globals@^13.15.0: + version "13.17.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== dependencies: - define-properties "^1.1.3" + type-fest "^0.20.2" globby@10.0.0: version "10.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.0.tgz#abfcd0630037ae174a88590132c2f6804e291072" + resolved "https://registry.npmjs.org/globby/-/globby-10.0.0.tgz" integrity sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw== dependencies: "@types/glob" "^7.1.1" @@ -9005,81 +7124,60 @@ globby@10.0.0: 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== +globby@^11.0.1, globby@^11.0.2, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" 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== +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz" + integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== + +got@^11.8.2: + version "11.8.5" + resolved "https://registry.npmjs.org/got/-/got-11.8.5.tgz" + integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== + 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" + +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.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 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= + integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== -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== +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== dependencies: - duplexer "^0.1.1" - pify "^4.0.1" + duplexer "^0.1.2" -handlebars@4.7.7, handlebars@^4.5.3, handlebars@^4.7.6, handlebars@^4.7.7: +handlebars@4.7.7, handlebars@^4.5.3, handlebars@^4.7.7: version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== dependencies: minimist "^1.2.5" @@ -9091,12 +7189,12 @@ handlebars@4.7.7, handlebars@^4.5.3, handlebars@^4.7.6, handlebars@^4.7.7: 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= + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== -har-validator@~5.1.0, har-validator@~5.1.3: +har-validator@~5.1.0: version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz" integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: ajv "^6.12.3" @@ -9104,50 +7202,57 @@ har-validator@~5.1.0, har-validator@~5.1.3: hard-rejection@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz" 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-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== 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= + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" 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-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" -has-unicode@^2.0.0, has-unicode@^2.0.1: +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= + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== 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= + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -9155,8 +7260,8 @@ has-value@^0.3.1: 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= + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz" + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -9164,142 +7269,70 @@ has-value@^1.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= + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz" + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== 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= + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz" + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== 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" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 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: +he@^1.1.0, he@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" 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" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +hosted-git-info@^3.0.6: + version "3.0.8" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz" + integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw== + dependencies: + lru-cache "^6.0.0" + 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== + version "4.1.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== dependencies: lru-cache "^6.0.0" -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== +hosted-git-info@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.1.0.tgz" + integrity sha512-Ek+QmMEqZF8XrbFdwoDjSbm7rT23pCgEMOJmz6GPk/s4yH//RQfNPArhIxbguNxROq/+5lNBwCDHMhA903Kx1Q== dependencies: - whatwg-encoding "^1.0.1" + lru-cache "^7.5.1" 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" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz" 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" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" 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" + resolved "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz" integrity sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA== dependencies: html-minifier-terser "^5.1.1" @@ -9307,9 +7340,9 @@ html-loader@~1.3.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -html-minifier-terser@^5.0.1, html-minifier-terser@^5.1.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" + resolved "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz" integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== dependencies: camel-case "^4.1.1" @@ -9320,48 +7353,38 @@ html-minifier-terser@^5.0.1, html-minifier-terser@^5.1.1: 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-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + 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" + +html-tags@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz" + integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg== 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== + version "5.5.0" + resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== dependencies: - "@types/html-minifier-terser" "^5.0.0" - html-minifier-terser "^5.0.1" + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" lodash "^4.17.21" - pretty-error "^3.0.4" + pretty-error "^4.0.0" tapable "^2.0.0" htmlparser2@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz" integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== dependencies: domelementtype "^2.0.1" @@ -9371,7 +7394,7 @@ htmlparser2@^4.1.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" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz" integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== dependencies: domelementtype "^2.0.1" @@ -9381,48 +7404,41 @@ htmlparser2@^6.0.0, htmlparser2@^6.1.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" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz" 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.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" - integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" + depd "2.0.0" inherits "2.0.4" setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -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= + statuses "2.0.1" + toidentifier "1.0.1" 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" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== dependencies: "@tootallnate/once" "1" agent-base "6" debug "4" +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + 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" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" @@ -9430,12 +7446,12 @@ http-proxy@^1.18.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== + version "13.1.0" + resolved "https://registry.npmjs.org/http-server/-/http-server-13.1.0.tgz" + integrity sha512-MLqBMXeY/YN0FYMz4ifeOQCcg8pKj8YdmzX1pr/Vb2VrNnbxHN1s4K9BuZRVSyK/j3DQ8UVrrABb8m6EmFjWog== dependencies: basic-auth "^1.0.3" - colors "^1.4.0" + chalk "^4.1.2" corser "^2.0.1" he "^1.1.0" http-proxy "^1.18.0" @@ -9449,496 +7465,341 @@ http-server@^13.0.0: 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= + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" -http-status-codes@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" - integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== +http-status-codes@2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz" + 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= +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" -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== +https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== 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" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" 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" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" 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= + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== dependencies: ms "^2.0.0" -husky@^4.2.5: - version "4.3.8" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" - integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== - dependencies: - chalk "^4.0.0" - ci-info "^2.0.0" - compare-versions "^3.6.0" - cosmiconfig "^7.0.0" - find-versions "^4.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^5.0.0" - please-upgrade-node "^3.2.0" - slash "^3.0.0" - which-pm-runs "^1.0.0" - -iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: +iconv-lite@0.6, iconv-lite@^0.6.2: version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" 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" + resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" 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= + resolved "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz" + integrity sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA== dependencies: harmony-reflect "^1.4.6" -ieee754@^1.1.13, ieee754@^1.1.4: +ieee754@^1.1.13: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" 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== +ignore-walk@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz" + integrity sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw== 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== + minimatch "^5.0.1" -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= +ignore@^5.0.4, ignore@^5.1.1, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== 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: +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" 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-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== 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== + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== 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= + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infer-owner@^1.0.3, infer-owner@^1.0.4: +infer-owner@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz" 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= + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 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: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 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= + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -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== +ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -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== +init-package-json@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-3.0.2.tgz" + integrity sha512-YhlQPEjNFqlGdzrBfDNRLhvoSgX7iQRgSxgsNknRQ9ITXFT7UMfVMWhBTOh2Y+25lRnGrv5Xz8yZwQ3ACR6T3A== dependencies: - glob "^7.1.1" - npm-package-arg "^8.1.2" + npm-package-arg "^9.0.1" promzard "^0.3.0" - read "~1.0.1" - read-package-json "^4.0.0" + read "^1.0.7" + read-package-json "^5.0.0" semver "^7.3.5" validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" + validate-npm-package-name "^4.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== +inquirer@^7.1.0: + version "7.3.3" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== dependencies: ansi-escapes "^4.2.1" - chalk "^2.4.2" + chalk "^4.1.0" cli-cursor "^3.1.0" - cli-width "^2.0.0" + cli-width "^3.0.0" external-editor "^3.0.3" figures "^3.0.0" - lodash "^4.17.15" + lodash "^4.17.19" mute-stream "0.0.8" - run-async "^2.2.0" - rxjs "^6.5.3" + run-async "^2.4.0" + rxjs "^6.6.0" 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" + strip-ansi "^6.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== +inquirer@^8.2.4: + version "8.2.4" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz" + integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg== dependencies: ansi-escapes "^4.2.1" - chalk "^4.1.0" + 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.19" + lodash "^4.17.21" mute-stream "0.0.8" + ora "^5.4.1" run-async "^2.4.0" - rxjs "^6.6.0" + rxjs "^7.5.5" string-width "^4.1.0" strip-ansi "^6.0.0" through "^2.3.6" + wrap-ansi "^7.0.0" internal-slot@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" 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== +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== -interpret@^2.0.0, interpret@^2.2.0: +interpret@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" 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-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - -ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" 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= + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz" + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== 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" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz" 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= + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-arrayish@^0.3.1: version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" 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= + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: - binary-extensions "^1.0.0" + has-bigints "^1.0.1" 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" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" 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== + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-buffer@^1.1.5, is-buffer@~1.1.6: +is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" 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-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== is-ci@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz" 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== +is-core-module@^2.5.0, is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-core-module@^2.8.1: + version "2.10.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== 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= + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz" + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== 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" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz" 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== + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz" integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" @@ -9947,349 +7808,250 @@ is-descriptor@^0.1.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" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" 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, is-docker@^2.1.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" 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= + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz" 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: +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= + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 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" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" 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== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 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-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== 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= + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-map@^2.0.2: +is-negative-zero@^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== + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== 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== + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" 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= + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== 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" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - is-obj@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" 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= + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz" + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== 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" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" 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" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" 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" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== is-promise@^2.1.0, is-promise@^2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz" 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== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.2" - -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + has-tostringtag "^1.0.0" -is-root@2.1.0: +is-regexp@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" - integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz" + integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== -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-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" -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== +is-ssh@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== dependencies: - protocols "^1.1.0" + protocols "^2.0.1" 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= + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== 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== + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -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-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" 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" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" 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= + resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz" + integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== 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= + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-window@^1.0.2: +is-weakref@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d" - integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0= + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" 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: +is-wsl@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" 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: +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== + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== 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= + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 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= + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== 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== + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== isomorphic.js@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.4.tgz#24ca374163ae54a7ce3b86ce63b701b91aa84969" - integrity sha512-Y4NjZceAwaPXctwsHgNsmfuPxR8lJ3f8X7QTAkhltrX4oGIv+eTlgHLXn4tWysC9zGTi929gapnPp+8F8cg7nA== + version "0.2.5" + resolved "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz" + 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= + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -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-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: +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" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" @@ -10297,9 +8059,20 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^5.0.4: + version "5.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + 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" + 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" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -10307,48 +8080,25 @@ istanbul-lib-report@^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== + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== 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== + version "3.1.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== 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" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz" integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: "@jest/types" "^26.6.2" @@ -10357,7 +8107,7 @@ jest-changed-files@^26.6.2: jest-cli@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz" integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: "@jest/core" "^26.6.3" @@ -10376,7 +8126,7 @@ jest-cli@^26.6.3: jest-config@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz" integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" @@ -10400,7 +8150,7 @@ jest-config@^26.6.3: 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" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz" integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: chalk "^4.0.0" @@ -10408,26 +8158,16 @@ jest-diff@^26.0.0, jest-diff@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-diff@^27.2.5: - version "27.3.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.3.1.tgz#d2775fea15411f5f5aeda2a5e02c2f36440f6d55" - integrity sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.0.6" - jest-get-type "^27.3.1" - pretty-format "^27.3.1" - jest-docblock@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz" 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" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz" integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: "@jest/types" "^26.6.2" @@ -10438,7 +8178,7 @@ jest-each@^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" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz" integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== dependencies: "@jest/environment" "^26.6.2" @@ -10451,7 +8191,7 @@ jest-environment-jsdom@^26.6.2: 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" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz" integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== dependencies: "@jest/environment" "^26.6.2" @@ -10463,17 +8203,12 @@ jest-environment-node@^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" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-get-type@^27.0.6, jest-get-type@^27.3.1: - version "27.3.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.3.1.tgz#a8a2b0a12b50169773099eee60a0e6dd11423eff" - integrity sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg== - 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" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz" integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: "@jest/types" "^26.6.2" @@ -10494,7 +8229,7 @@ jest-haste-map@^26.6.2: jest-jasmine2@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz" integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" @@ -10518,7 +8253,7 @@ jest-jasmine2@^26.6.3: jest-junit@^11.1.0: version "11.1.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" + resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-11.1.0.tgz" integrity sha512-c2LFOyKY7+ZxL5zSu+WHmHfsJ2wqbOpeYJ4Uu26yMhFxny2J2NQj6AVS7M+Eaxji9Q/oIDDK5tQy0DGzDp9xOw== dependencies: mkdirp "^1.0.4" @@ -10528,25 +8263,15 @@ jest-junit@^11.1.0: 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" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz" integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-matcher-utils@=27.2.5, jest-matcher-utils@^27.2.5: - version "27.2.5" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz#4684faaa8eb32bf15e6edaead6834031897e2980" - integrity sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg== - dependencies: - chalk "^4.0.0" - jest-diff "^27.2.5" - jest-get-type "^27.0.6" - pretty-format "^27.2.5" - 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" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz" integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: chalk "^4.0.0" @@ -10556,7 +8281,7 @@ jest-matcher-utils@^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" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz" integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" @@ -10569,24 +8294,9 @@ jest-message-util@^26.6.2: slash "^3.0.0" stack-utils "^2.0.2" -jest-message-util@^27.2.5: - version "27.3.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.3.1.tgz#f7c25688ad3410ab10bcb862bcfe3152345c6436" - integrity sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.2.5" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.4" - pretty-format "^27.3.1" - slash "^3.0.0" - stack-utils "^2.0.3" - jest-mock@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz" integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: "@jest/types" "^26.6.2" @@ -10594,27 +8304,22 @@ jest-mock@^26.6.2: 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" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" 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= + resolved "https://registry.npmjs.org/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz" + integrity sha512-g9oaAjeC4/rIJk1Wd3RxVbOfMizowM7LSjEJqa4R9qDX0OjQNABXOhH+GaznUp+DjTGVPi2vPPbQXyX87DOnYg== 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" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-regex-util@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" - integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== - 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" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz" integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: "@jest/types" "^26.6.2" @@ -10623,7 +8328,7 @@ jest-resolve-dependencies@^26.6.3: jest-resolve@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz" integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: "@jest/types" "^26.6.2" @@ -10637,12 +8342,12 @@ jest-resolve@^26.6.2: jest-retries@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/jest-retries/-/jest-retries-1.0.1.tgz#b60eac2c6f6ee7033fbc9a3cb6f3016a63b82822" + resolved "https://registry.npmjs.org/jest-retries/-/jest-retries-1.0.1.tgz" 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" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz" integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: "@jest/console" "^26.6.2" @@ -10668,7 +8373,7 @@ jest-runner@^26.6.3: jest-runtime@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz" integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== dependencies: "@jest/console" "^26.6.2" @@ -10701,7 +8406,7 @@ jest-runtime@^26.6.3: jest-serializer@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz" integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== dependencies: "@types/node" "*" @@ -10709,7 +8414,7 @@ jest-serializer@^26.6.2: jest-snapshot@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz" integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" @@ -10731,14 +8436,14 @@ jest-snapshot@^26.6.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" + resolved "https://registry.npmjs.org/jest-summary-reporter/-/jest-summary-reporter-0.0.2.tgz" 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" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: "@jest/types" "^26.6.2" @@ -10750,7 +8455,7 @@ jest-util@^26.1.0, jest-util@^26.6.2: jest-validate@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz" integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: "@jest/types" "^26.6.2" @@ -10762,7 +8467,7 @@ jest-validate@^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" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz" integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: "@jest/test-result" "^26.6.2" @@ -10773,19 +8478,19 @@ jest-watcher@^26.6.2: 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: +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" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz" 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== +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== dependencies: "@types/node" "*" merge-stream "^2.0.0" @@ -10793,43 +8498,28 @@ jest-worker@^27.0.2: jest@^26.4.2: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + resolved "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz" 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, jpeg-js@^0.4.2: - 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" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 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: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" -js-yaml@^3.13.1: +js-yaml@^3.12.1, js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -10837,45 +8527,13 @@ js-yaml@^3.13.1: jsbn@~0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@15.2.1: - version "15.2.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== - dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^7.0.0" - xml-name-validator "^3.0.0" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -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== +jsdom@16.7.0, jsdom@^16.4.0: + version "16.7.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== dependencies: abab "^2.0.5" acorn "^8.2.4" @@ -10902,155 +8560,171 @@ jsdom@^16.4.0: whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" whatwg-url "^8.5.0" - ws "^7.4.5" + ws "^7.4.6" 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" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" 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= + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== -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-buffer@3.0.1, json-buffer@~3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-parse-even-better-errors@^2.3.0: +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 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" + resolved "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz" 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" + resolved "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.6.0.tgz" integrity sha512-LEw4VMQVRceOPLuGRWcxW5orTTiR9ZAtqTAe4rQUjNADTeR81bezBVFa0MqIwp0YmHIM1KkhSjZM7o+IQhaPbQ== dependencies: compute-lcm "^1.1.0" json-schema-compare "^0.2.2" lodash "^4.17.4" +json-schema-ref-parser@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz" + integrity sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw== + dependencies: + call-me-maybe "^1.0.1" + js-yaml "^3.12.1" + ono "^4.0.11" + +json-schema-to-typescript@^8.0.0: + version "8.2.0" + resolved "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-8.2.0.tgz" + integrity sha512-yvi4v9oLeJzJCktt+Zta6kOgEu8R93gNMZUJYo83aAPxoG0qB+cXIxVg5xa6gmdNkyffjH9Ebw1rvyaJKIor5A== + 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" + 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" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -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-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@~0.4.0: +json-schema@0.4.0, json-schema@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" 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= + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json-stringify-nice@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz" + integrity sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw== 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" + resolved "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz" 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= + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== 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= + resolved "https://registry.npmjs.org/json-to-html/-/json-to-html-0.1.2.tgz" + integrity sha512-gwezGNdnxPnp+7m5aVFq080KGjURyLqLAMmoRlkfnapQYluxQX18Hu+MOPYOtPaipYSB1bawQem5cmvRo/aAMA== json2html@^0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/json2html/-/json2html-0.0.8.tgz#6c64ee08259744fd28a49fb97d7746b29ae0501d" - integrity sha1-bGTuCCWXRP0opJ+5fXdGsprgUB0= + resolved "https://registry.npmjs.org/json2html/-/json2html-0.0.8.tgz" + integrity sha512-WwGOLuGAqD9xv0rfS6g6R/ZWO9GDceR/68HGMaw7RXACU8+bRbQ94JTdVOtKhchRBPGK9jLzM0U7HR1kLWfPdA== 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@2.x, json5@^2.1.1, json5@^2.1.2, json5@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== json5@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz" 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" +jsonc-parser@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz" + integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== + +jsonc-parser@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz" + integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg== jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" 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= + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -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== +jsonpointer@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== jsonwebtoken@8.5.1: version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== dependencies: jws "^3.2.2" @@ -11065,26 +8739,36 @@ jsonwebtoken@8.5.1: semver "^5.6.0" jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + version "1.4.2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" - json-schema "0.2.3" + json-schema "0.4.0" verror "1.10.0" "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== + version "3.3.2" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz" + integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q== dependencies: - array-includes "^3.1.2" + array-includes "^3.1.5" object.assign "^4.1.2" +just-diff-apply@^5.2.0: + version "5.4.1" + resolved "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.4.1.tgz" + integrity sha512-AAV5Jw7tsniWwih8Ly3fXxEZ06y+6p5TwQMsw0dzZ/wPKilzyDgdAnL0Ug4NNIquPUOh1vfFWEHbmXUqM5+o8g== + +just-diff@^5.0.1: + version "5.1.1" + resolved "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz" + integrity sha512-u8HXJ3HlNrTzY7zrYYKjNEfBlyjqhdBkoyTVdjtn7p02RJD5NvR8rIClzeGA7t+UYP1/7eAkWNLU0+P3QrEqKQ== + jwa@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + resolved "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz" integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== dependencies: buffer-equal-constant-time "1.0.1" @@ -11093,7 +8777,7 @@ jwa@^1.4.1: jws@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + resolved "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== dependencies: jwa "^1.4.1" @@ -11101,107 +8785,82 @@ jws@^3.2.2: keygrip@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" + resolved "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz" 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== +keyv@^4.0.0: + version "4.3.3" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.3.3.tgz" + integrity sha512-AcysI17RvakTh8ir03+a3zJr5r0ovnAH/XTXei/4HIv3bL2K/jzvgivLK9UuI/JbU1aJjM3NSAnVvVVd3n+4DQ== dependencies: - json-buffer "3.0.0" + compress-brotli "^1.3.8" + json-buffer "3.0.1" 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= + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== 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= + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== 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" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" 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" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" 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.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" - integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== +kleur@4.1.5: + version "4.1.5" + resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz" + 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" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" 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" +known-css-properties@^0.25.0: + version "0.25.0" + resolved "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz" + integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA== + +lerna@^5.4.3: + version "5.4.3" + resolved "https://registry.npmjs.org/lerna/-/lerna-5.4.3.tgz" + integrity sha512-PypijMk4Jii8DoWGRLiHhBUaqpjXAmrwbs6uUZgyb07JrqCrXW3nhAyzdZE5S0rk1/sRzjd10fYmntOgNFfKBw== + dependencies: + "@lerna/add" "5.4.3" + "@lerna/bootstrap" "5.4.3" + "@lerna/changed" "5.4.3" + "@lerna/clean" "5.4.3" + "@lerna/cli" "5.4.3" + "@lerna/create" "5.4.3" + "@lerna/diff" "5.4.3" + "@lerna/exec" "5.4.3" + "@lerna/import" "5.4.3" + "@lerna/info" "5.4.3" + "@lerna/init" "5.4.3" + "@lerna/link" "5.4.3" + "@lerna/list" "5.4.3" + "@lerna/publish" "5.4.3" + "@lerna/run" "5.4.3" + "@lerna/version" "5.4.3" import-local "^3.0.2" - npmlog "^4.1.2" + npmlog "^6.0.2" + nx ">=14.5.4 < 16" level-codec@^9.0.0: version "9.0.2" @@ -11287,12 +8946,12 @@ levelup@^4.3.2: leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" 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" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -11300,137 +8959,64 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" -lib0@^0.2.31, lib0@^0.2.42: - version "0.2.42" - resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.42.tgz#6d8bf1fb8205dec37a953c521c5ee403fd8769b0" - integrity sha512-8BNM4MiokEKzMvSxTOC3gnCBisJH+jL67CnSnqzHv3jli3pUvGC8wz+0DQ2YvGr4wVQdb2R2uNNPw9LEpVvJ4Q== +lib0@^0.2.31: + version "0.2.52" + resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.52.tgz#f07c975673ab3273e676712860d941f996e5fe79" + integrity sha512-CjxlM7UgICfN6b2OPALBXchIBiNk6jE+1g7JP8ha+dh1xKRDSYpH0WQl1+rMqCju49xUnwPG34v4CR5/rPOZhg== 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== +lib0@^0.2.42, lib0@^0.2.49: + version "0.2.51" + resolved "https://registry.npmjs.org/lib0/-/lib0-0.2.51.tgz" + integrity sha512-05Erb3465CxJa38LQlMz4EbetNvRna1S3BzqEjC0/pmp5cQuQSfNNmeS0722Wev1dRlMUp2Cql0gQ55krSXf2Q== + dependencies: + isomorphic.js "^0.2.4" + +libnpmaccess@^6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-6.0.3.tgz" + integrity sha512-4tkfUZprwvih2VUZYMozL7EMKgQ5q9VW2NtRyxWtQWlkLTAWHRklcAvBN49CVqEkhUw7vTX2fNgB5LzgUucgYg== dependencies: aproba "^2.0.0" minipass "^3.1.1" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" + npm-package-arg "^9.0.1" + npm-registry-fetch "^13.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== +libnpmpublish@^6.0.4: + version "6.0.4" + resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-6.0.4.tgz" + integrity sha512-lvAEYW8mB8QblL6Q/PI/wMzKNvIrF7Kpujf/4fGS/32a2i3jzUXi04TNyIBcK6dQJ34IgywfaKGh+Jq4HYPFmg== 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" + normalize-package-data "^4.0.0" + npm-package-arg "^9.0.1" + npm-registry-fetch "^13.0.0" + semver "^7.3.7" + ssri "^9.0.0" 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== + version "2.3.21" + resolved "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.3.21.tgz" + integrity sha512-rVaYU9TddZN3ao8M/0PrRSCdTp2EW6VQymlgsuScld1vef0Ou7fALx3ePe83KLP3xAEDcPK5fkqUVqGBnbz1zQ== 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= - -lint-staged@^10.2.13: - version "10.5.4" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.4.tgz#cd153b5f0987d2371fc1d2847a409a2fe705b665" - integrity sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg== - dependencies: - chalk "^4.1.0" - cli-truncate "^2.1.0" - commander "^6.2.0" - cosmiconfig "^7.0.0" - debug "^4.2.0" - dedent "^0.7.0" - enquirer "^2.3.6" - execa "^4.1.0" - listr2 "^3.2.2" - log-symbols "^4.0.0" - micromatch "^4.0.2" - normalize-path "^3.0.0" - please-upgrade-node "^3.2.0" - string-argv "0.3.1" - stringify-object "^3.3.0" - -listr2@^3.2.2: - version "3.10.0" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.10.0.tgz#58105a53ed7fa1430d1b738c6055ef7bb006160f" - integrity sha512-eP40ZHihu70sSmqFNbNy2NL1YwImmlMmPh9WO5sLmPDleurMHt3n+SwEWNu2kzKScexZnkyFtc1VI0z/TGlmpw== - dependencies: - cli-truncate "^2.1.0" - colorette "^1.2.2" - log-update "^4.0.0" - p-map "^4.0.0" - rxjs "^6.6.7" - through "^2.3.8" - wrap-ansi "^7.0.0" + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 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= + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz" + integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== dependencies: graceful-fs "^4.1.2" parse-json "^4.0.0" @@ -11439,7 +9025,7 @@ load-json-file@^4.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" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz" integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== dependencies: graceful-fs "^4.1.15" @@ -11447,38 +9033,24 @@ load-json-file@^6.2.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" + version "4.3.0" + resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== -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: +loader-utils@^1.0.0, loader-utils@^1.0.3: version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" json5 "^1.0.1" -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== +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" @@ -11486,273 +9058,188 @@ loader-utils@^2.0.0, loader-utils@~2.0.0: 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= + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== 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" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" 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" + resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz" integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== dependencies: signal-exit "^3.0.2" -lodash-es@^4.17.15: - 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= + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== 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= + resolved "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz" + integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA== 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= + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== 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= + resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz" + integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw== lodash.includes@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== lodash.isboolean@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= - -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= + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== lodash.isinteger@^4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== 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= + resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz" + integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== lodash.isnumber@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + resolved "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.isstring@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== -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.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.mergewith@^4.6.1: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== -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.once@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== -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.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -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: +lodash@4, lodash@4.17.21, lodash@4.x, 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.7.0: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 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" - -log-symbols@^4.0.0: +log-symbols@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - -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: +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" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" lowdb@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064" + resolved "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz" 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= + steno "^0.4.1" lower-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" 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" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" 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.13.1: + version "7.13.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz" + integrity sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ== -lru-cache@6.0.0, lru-cache@^6.0.0: +lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" -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@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: + version "7.13.2" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz" + integrity sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA== lru-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" - integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + resolved "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz" + integrity sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ== dependencies: es5-ext "~0.10.2" ltgt@^2.1.2: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== 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" + resolved "https://registry.npmjs.org/lunr-mutable-indexes/-/lunr-mutable-indexes-2.3.2.tgz" 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" + resolved "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz" integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== dependencies: pify "^4.0.1" @@ -11760,178 +9247,90 @@ make-dir@^2.0.0, make-dir@^2.1.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" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" 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" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" 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== +make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: + version "10.2.1" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz" + integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" + agentkeepalive "^4.2.1" + cacache "^16.1.0" http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" + http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0" is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" + lru-cache "^7.7.1" + minipass "^3.1.6" minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" + minipass-fetch "^2.0.3" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" - negotiator "^0.6.2" + negotiator "^0.6.3" promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" + socks-proxy-agent "^7.0.0" + ssri "^9.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= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" 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= + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== 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= + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== 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= + version "4.3.0" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== 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= + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz" + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== 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@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/marked/-/marked-2.0.5.tgz#2d15c759b9497b0e7b5b57f4c2edabe1002ef9e7" - integrity sha512-yfCEUXmKhBPLOzEC7c+tc4XZdIeTdGoRCZakFMkCxodr7wDXqoapIME4wjcpBPJLNyUnKJ3e8rb8wlAgnLnaDw== - -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@4.0.18, marked@^4.0.16, marked@^4.0.17: + version "4.0.18" + resolved "https://registry.npmjs.org/marked/-/marked-4.0.18.tgz" + integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== -marked@^2.0.0, marked@^2.0.1, marked@^2.1.1: +mathml-tag-names@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/marked/-/marked-2.1.3.tgz#bd017cef6431724fd4b27e0657f5ceb14bff3753" - integrity sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA== - -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" + resolved "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz" + integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== mdn-data@2.0.14: version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz" 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= + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -memoizee@0.4.15: +memoizee@0.4.15, memoizee@^0.4.14: version "0.4.15" - resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" + resolved "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz" integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== dependencies: d "^1.0.1" @@ -11943,53 +9342,31 @@ memoizee@0.4.15: next-tick "^1.1.0" timers-ext "^0.1.7" -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== +meow@^8.0.0: + version "8.1.2" + resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz" + 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 "^2.5.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.13.1" - yargs-parser "^18.1.3" + type-fest "^0.18.0" + yargs-parser "^20.2.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== +meow@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz" + integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== dependencies: "@types/minimist" "^1.2.0" camelcase-keys "^6.2.2" + decamelize "^1.2.0" decamelize-keys "^1.1.0" hard-rejection "^2.1.0" minimist-options "4.1.0" @@ -12002,42 +9379,27 @@ meow@^8.0.0: 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= + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" 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== + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" @@ -12054,144 +9416,145 @@ micromatch@^3.1.10, micromatch@^3.1.4: 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== +micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" + braces "^3.0.2" + picomatch "^2.3.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, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + 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== +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.48.0" + 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" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@2.5.2, mime@^2.4.4, mime@^2.4.6: - 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== +mime@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" 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" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz" 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" +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== min-indent@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" 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" + resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.9.tgz" 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== +mini-svg-data-uri@^1.4.4: + version "1.4.4" + resolved "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz" + integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== -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.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, 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== +minimatch@3.0.5: + version "3.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz" + integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@5.1.0, minimatch@^5.0.1, minimatch@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz" + integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@~3.0.4: + version "3.0.8" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== 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" + resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" 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== +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0: + version "1.2.6" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz" 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== +minipass-fetch@^2.0.3: + version "2.1.0" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz" + integrity sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg== dependencies: - minipass "^3.1.0" + minipass "^3.1.6" minipass-sized "^1.0.3" - minizlib "^2.0.0" + minizlib "^2.1.2" optionalDependencies: - encoding "^0.1.12" + encoding "^0.1.13" minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" 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" + resolved "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz" integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== dependencies: jsonparse "^1.3.1" @@ -12199,67 +9562,36 @@ minipass-json-stream@^1.0.1: 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" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" 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" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" 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== +minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: + version "3.3.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz" + integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== 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: +minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" 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" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" @@ -12267,7 +9599,7 @@ mixin-deep@^1.2.0: 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" + resolved "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz" integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== dependencies: chownr "^2.0.0" @@ -12276,56 +9608,49 @@ mkdirp-infer-owner@^2.0.0: 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" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" 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== +mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" modify-values@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" + resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== moment@^2.24.0: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + version "2.29.4" + resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== -move-concurrently@^1.0.1: +mrmime@^1.0.0: 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" + resolved "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz" + integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== 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== + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: +ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + 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" + resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz" integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== dependencies: "@types/minimatch" "^3.0.3" @@ -12334,38 +9659,42 @@ multimatch@^5.0.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" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" 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= + resolved "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz" + integrity sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg== dependencies: mkdirp "~0.5.1" ncp "~2.0.0" rimraf "~2.4.0" -nan@^2.12.1, nan@^2.14.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@^2.15.0: + version "2.16.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz" + integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== -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== +nanoid@^3.1.23, nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== nanomatch@^1.2.9: version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz" integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" @@ -12387,147 +9716,84 @@ napi-macros@~2.0.0: 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= + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== ncp@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" - integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + resolved "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz" + integrity sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA== -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, negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + 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: +neo-async@^2.6.0, neo-async@^2.6.2: version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== next-tick@1, next-tick@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -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" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" 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" + resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" 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-addon-api@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== -node-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@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" -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.3.0: + version "4.5.0" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== 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== +node-gyp@^9.0.0: + version "9.1.0" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-9.1.0.tgz" + integrity sha512-HkmN0ZpQJU7FLbJauJTHkHlSVAXlNGDAzH/VYFZGDOnFyn/Na3GlNJfkudmufOdS6/jNFhy88ObzL7ERz9es1g== dependencies: env-paths "^2.2.0" glob "^7.1.4" - graceful-fs "^4.2.3" + graceful-fs "^4.2.6" + make-fetch-happen "^10.0.3" nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" + npmlog "^6.0.0" rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" + semver "^7.3.5" + tar "^6.1.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= + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== node-notifier@^8.0.0: version "8.0.2" @@ -12541,29 +9807,21 @@ node-notifier@^8.0.0: 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" +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== nopt@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz" 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" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" @@ -12571,9 +9829,9 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: +normalize-package-data@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" @@ -12581,234 +9839,233 @@ normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: semver "^7.3.4" validate-npm-package-license "^3.0.1" +normalize-package-data@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz" + integrity sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg== + dependencies: + hosted-git-info "^5.0.0" + is-core-module "^2.8.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + 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= + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== 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" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" 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: +normalize-url@^6.0.1, normalize-url@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" 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: +npm-bundled@^1.1.1, npm-bundled@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz" 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== +npm-install-checks@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz" + integrity sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA== 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" + resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz" 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== +npm-package-arg@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.1.tgz" + integrity sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg== dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" + hosted-git-info "^3.0.6" + semver "^7.0.0" 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== +npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: + version "9.1.0" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz" + integrity sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw== dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" + hosted-git-info "^5.0.0" + proc-log "^2.0.1" + semver "^7.3.5" + validate-npm-package-name "^4.0.0" -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== +npm-packlist@^5.1.0, npm-packlist@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz" + integrity sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw== dependencies: - npm-install-checks "^4.0.0" + glob "^8.0.1" + ignore-walk "^5.0.1" + npm-bundled "^1.1.2" 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== +npm-pick-manifest@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz" + integrity sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg== 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-install-checks "^5.0.0" + npm-normalize-package-bin "^1.0.1" + npm-package-arg "^9.0.0" + semver "^7.3.5" -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== +npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3.0: + version "13.3.1" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz" + integrity sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw== 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" + make-fetch-happen "^10.0.6" + minipass "^3.1.6" + minipass-fetch "^2.0.3" minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" + minizlib "^2.1.2" + npm-package-arg "^9.0.1" + proc-log "^2.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= + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== 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" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" 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== +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + 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== +npmlog@^6.0.0, npmlog@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== dependencies: - boolbase "~1.0.0" + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.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== +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== 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" + resolved "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz" 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== + version "2.2.1" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz" + integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg== + +nx@14.5.6, "nx@>=14.5.4 < 16": + version "14.5.6" + resolved "https://registry.npmjs.org/nx/-/nx-14.5.6.tgz" + integrity sha512-HqOCRKBFPyyauZVTHyF7l5x97xYGukTjeQXxZD5LdVxiL1lSyaOtBCTNUmOge/jCPH3crvSeV2Wt58ZF4u0yaw== + dependencies: + "@nrwl/cli" "14.5.6" + "@nrwl/tao" "14.5.6" + "@parcel/watcher" "2.0.4" + chalk "4.1.0" + chokidar "^3.5.1" + 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 "^10.1.0" + glob "7.1.4" + ignore "^5.0.4" + js-yaml "4.1.0" + jsonc-parser "3.0.0" + minimatch "3.0.5" + npm-run-path "^4.0.1" + open "^8.4.0" + semver "7.3.4" + string-width "^4.2.3" + tar-stream "~2.2.0" + tmp "~0.2.1" + tsconfig-paths "^3.9.0" + tslib "^2.3.0" + v8-compile-cache "2.3.0" + yargs "^17.4.0" + yargs-parser "21.0.1" oauth-sign@~0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, 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= + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 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= + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== 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-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" 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= + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz" + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== 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" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: call-bind "^1.0.0" @@ -12816,132 +10073,108 @@ object.assign@^4.1.0, object.assign@^4.1.2: 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== +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" -"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== +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" + es-abstract "^1.19.1" -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== +object.getownpropertydescriptors@^2.0.3: + version "2.1.4" + resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz" + integrity sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ== dependencies: + array.prototype.reduce "^1.0.4" call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + define-properties "^1.1.4" + es-abstract "^1.20.1" + +object.hasown@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz" + integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== + dependencies: + define-properties "^1.1.4" + es-abstract "^1.19.5" 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= + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== 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== +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== 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== + es-abstract "^1.19.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= +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 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" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" 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= + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 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" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" 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== +ono@^4.0.11: + version "4.0.11" + resolved "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz" + integrity sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g== dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" + format-util "^1.0.3" -open@^8.3.0: +open@^8.4.0: version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + resolved "https://registry.npmjs.org/open/-/open-8.4.0.tgz" integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== dependencies: define-lazy-prop "^2.0.0" is-docker "^2.1.1" is-wsl "^2.2.0" -opencollective-postinstall@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - -opener@^1.5.1: +opener@^1.5.1, opener@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" 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" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -12953,7 +10186,7 @@ optionator@^0.8.1: optionator@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: deep-is "^0.1.3" @@ -12963,130 +10196,101 @@ optionator@^0.9.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= +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== dependencies: - lcid "^1.0.0" + 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" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +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= + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== 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== + version "0.1.2" + resolved "https://registry.npmjs.org/os/-/os-0.1.2.tgz" + integrity sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ== -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-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== 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" + resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz" 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= + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== p-limit@^1.1.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" -p-limit@^3.0.2, p-limit@^3.1.0: +p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" 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= + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== 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" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" 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" + resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" 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" + resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz" 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" + resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz" integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== dependencies: eventemitter3 "^4.0.4" @@ -13094,92 +10298,73 @@ p-queue@^6.6.2: 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" + resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz" 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" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz" 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= + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" 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" + resolved "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz" 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== +package-json@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz" + integrity sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA== dependencies: - got "^9.6.0" + got "^11.8.2" registry-auth-token "^4.0.0" registry-url "^5.0.0" - semver "^6.2.0" + semver "^7.3.5" -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== +pacote@^13.0.3, pacote@^13.6.1: + version "13.6.1" + resolved "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz" + integrity sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw== 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" + "@npmcli/git" "^3.0.0" + "@npmcli/installed-package-contents" "^1.0.7" + "@npmcli/promise-spawn" "^3.0.0" + "@npmcli/run-script" "^4.1.0" + cacache "^16.0.0" 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" + minipass "^3.1.6" + mkdirp "^1.0.4" + npm-package-arg "^9.0.0" + npm-packlist "^5.1.0" + npm-pick-manifest "^7.0.0" + npm-registry-fetch "^13.0.1" + proc-log "^2.0.0" promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" + read-package-json "^5.0.0" + read-package-json-fast "^2.0.3" 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" + ssri "^9.0.0" + tar "^6.1.11" -param-case@^3.0.3: +param-case@^3.0.3, param-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz" integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== dependencies: dot-case "^3.0.4" @@ -13187,50 +10372,31 @@ param-case@^3.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" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" 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== +parse-conflict-json@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz" + integrity sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA== 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" + json-parse-even-better-errors "^2.3.1" + just-diff "^5.0.1" + just-diff-apply "^5.2.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= + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== 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" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -13240,52 +10406,44 @@ parse-json@^5.0.0: parse-ms@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" + resolved "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== -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== +parse-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz" + integrity sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A== dependencies: - is-ssh "^1.3.0" - protocols "^1.4.0" - qs "^6.9.4" - query-string "^6.13.8" + protocols "^2.0.0" 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= + resolved "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz" + integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q== -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== +parse-url@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz" + integrity sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg== dependencies: - is-ssh "^1.3.0" + is-ssh "^1.4.0" normalize-url "^6.1.0" - parse-path "^4.0.0" - protocols "^1.4.0" - -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + parse-path "^5.0.0" + protocols "^2.0.1" parse5@6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseurl@~1.3.2, parseurl@~1.3.3: +parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" 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" + resolved "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz" integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== dependencies: no-case "^3.0.4" @@ -13293,260 +10451,147 @@ pascal-case@^3.1.2: 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== + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== path-browserify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz" 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= + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" 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= + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 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= + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== 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" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" 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= + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== path-type@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" 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= + resolved "https://registry.npmjs.org/path/-/path-0.12.7.tgz" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== 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" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - 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= + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== picocolors@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" 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== +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== 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= + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pify@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" 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" + resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz" integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== pino-std-serializers@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" + resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz" integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== -pino@6.11.3: - version "6.11.3" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.11.3.tgz#0c02eec6029d25e6794fdb6bbea367247d74bc29" - integrity sha512-drPtqkkSf0ufx2gaea3TryFiBHdNIdXKf5LN0hTM82SXI4xVIve2wLwNg92e1MT6m3jASLu6VO7eGY6+mmGeyw== +pino@6.14.0: + version "6.14.0" + resolved "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz" + integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== dependencies: fast-redact "^3.0.0" - fast-safe-stringify "^2.0.7" + fast-safe-stringify "^2.0.8" flatstr "^1.0.12" pino-std-serializers "^3.1.0" + process-warning "^1.0.0" quick-format-unescaped "^4.0.3" sonic-boom "^1.0.2" -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" - -pixelmatch@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" - integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== - dependencies: - pngjs "^4.0.1" - -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" +pirates@^4.0.1: + version "4.0.5" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== 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" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.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.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.16.2.tgz#13c4c352a41e431ba167dbadb80e8c628e1e1b79" - integrity sha512-8WkoP5OfZAYrRxtW/PCVACn9bNgqrTxVVPlc+MoxvJ48knNsZ+skrPjfno/XF3SgTUY9DyYX0g5fVOB7lkPtGg== - dependencies: - commander "^8.2.0" - debug "^4.1.1" - extract-zip "^2.0.1" - https-proxy-agent "^5.0.0" - jpeg-js "^0.4.2" - mime "^2.4.6" - pngjs "^5.0.0" - progress "^2.0.3" - proper-lockfile "^4.1.1" - proxy-from-env "^1.1.0" - rimraf "^3.0.2" - socks-proxy-agent "^6.1.0" - stack-utils "^2.0.3" - ws "^7.4.6" - yauzl "^2.10.0" - yazl "^2.5.1" + resolved "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz" + integrity sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ== -please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== - dependencies: - semver-compare "^1.0.0" - -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - -pngjs@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" - integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== - -pngjs@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" - integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== - -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== +playwright-core@1.24.2: + version "1.24.2" + resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.24.2.tgz" + integrity sha512-zfAoDoPY/0sDLsgSgLZwWmSCevIg1ym7CppBwllguVBNiHeixZkc1AdMuYUPZC6AdEYc4CxWEyLMBTw2YcmRrA== portfinder@^1.0.25: version "1.0.28" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz" integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== dependencies: async "^2.6.2" @@ -13555,177 +10600,117 @@ portfinder@^1.0.25: 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" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz" + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== -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-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz" + integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== 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" + resolved "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz" 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" + resolved "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz" 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== +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz" + integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== + +postcss-safe-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz" + integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== + +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.10" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== 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-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -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== +postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.7: + version "8.4.14" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== dependencies: - nanoid "^3.1.30" + nanoid "^3.3.4" picocolors "^1.0.0" - source-map-js "^0.6.2" + source-map-js "^1.0.2" prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" 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= + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== prettier-bytes@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.4.tgz#994b02aa46f699c50b6257b5faaa7fe2557e62d6" - integrity sha1-mUsCqkb2mcULYle1+qp/4lV+YtY= + resolved "https://registry.npmjs.org/prettier-bytes/-/prettier-bytes-1.0.4.tgz" + integrity sha512-dLbWOa4xBn+qeWeIF60qRoB6Pk2jX5P3DIVgOQyMyvBpu931Q+8dXz8X0snJiFkQdohDDLnZQECjzsAj75hgZQ== 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" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" 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== +prettier@^1.19.1: + version "1.19.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -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" +prettier@~2.6.0: + version "2.6.2" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz" + integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== -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== +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== dependencies: lodash "^4.17.20" - renderkid "^2.0.6" + renderkid "^3.0.0" 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" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== dependencies: "@jest/types" "^26.6.2" @@ -13733,345 +10718,200 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^27.2.5, pretty-format@^27.3.1: - version "27.3.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.3.1.tgz#7e9486365ccdd4a502061fa761d3ab9ca1b78df5" - integrity sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA== - dependencies: - "@jest/types" "^27.2.5" - ansi-regex "^5.0.1" - ansi-styles "^5.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= - -pretty-ms@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-5.1.0.tgz#b906bdd1ec9e9799995c372e2b1c34f073f95384" - integrity sha512-4gaK1skD2gwscCfkswYQRmddUb2GJZtzDGRjHWadVHtK/DIKFufa12MvES6/xu1tVbUYeia5bmLcwJtZJQUqnw== +pretty-ms@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz" + integrity sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q== dependencies: parse-ms "^2.1.0" -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== +proc-log@^2.0.0, proc-log@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz" + integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw== 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" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process-warning@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz" + 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= + resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -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-all-reject-late@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz" + integrity sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw== + +promise-call-limit@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz" + integrity sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q== 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= + resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" 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== + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== 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= + resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz" + integrity sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw== 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== +prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" - -proper-lockfile@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" - integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== - dependencies: - graceful-fs "^4.2.4" - retry "^0.12.0" - signal-exit "^3.0.2" - -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" + react-is "^16.13.1" 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= + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -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== +protocols@^2.0.0, protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== -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" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - 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" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -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" +psl@^1.1.24, psl@^1.1.33: + version "1.9.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" 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: +punycode@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" 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: +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.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -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== +qs@6.10.3: + version "6.10.3" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== 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== +qs@^6.4.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== 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= + side-channel "^1.0.4" -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= +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== querystringify@^2.1.1: version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" 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" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" 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== + version "4.0.4" + resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== quick-lru@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz" 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= +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +randombytes@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" 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: +range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" 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== +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: - bytes "3.1.0" - http-errors "1.7.2" + 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: +rc@1.2.8, rc@^1.2.8: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -14079,162 +10919,31 @@ rc@^1.2.8: 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-base16-styling@^0.9.1: + version "0.9.1" + resolved "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz" + integrity sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw== + 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" react-dom@^17.0.1: version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" 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" + resolved "https://registry.npmjs.org/react-highlighter/-/react-highlighter-0.4.3.tgz" integrity sha512-dwItRaGRHBceuzZd5NXeroapdmZ2JCAWZ3AdwdthRlSkdtPCY18DWrd6mPmiMCfSB6lgVwwCPQl4unZzG5sXXw== dependencies: blacklist "^1.1.4" @@ -14242,146 +10951,49 @@ react-highlighter@^0.4.3: 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: +react-is@^16.13.1, react-is@^16.9.0: version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" 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" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" 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== +react-json-tree@^0.16.1: + version "0.16.2" + resolved "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.16.2.tgz" + integrity sha512-80F7ZTqeOl1YaS/sDce4tYBcSe69/d0mlUmcIhyXezPFctWrtvyN56EMExX9jWsq3XMdvsUKKPUeNo8QCBy2jg== 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== + "@babel/runtime" "^7.17.8" + "@types/prop-types" "^15.7.4" + prop-types "^15.8.1" + react-base16-styling "^0.9.1" react-paginate@^6.3.2: version "6.5.0" - resolved "https://registry.yarnpkg.com/react-paginate/-/react-paginate-6.5.0.tgz#b9baf53627b115cfd688afa048776aa45bffda19" + resolved "https://registry.npmjs.org/react-paginate/-/react-paginate-6.5.0.tgz" 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-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" + resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" 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-cmd-shim@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-3.0.0.tgz" + integrity sha512-KQDVjGqhZk92PPNRj9ZEXEuqg8bUobSKRw+q0YQ3TKI5xkce7bUJobL4Z/OtiEbAAv70yEpYIXp4iQ9L8oPVog== -read-package-json-fast@^2.0.1: +read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== dependencies: json-parse-even-better-errors "^2.3.0" @@ -14389,7 +11001,7 @@ read-package-json-fast@^2.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" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz" integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== dependencies: glob "^7.1.1" @@ -14397,29 +11009,19 @@ read-package-json@^2.0.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== +read-package-json@^5.0.0, read-package-json@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.1.tgz" + integrity sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg== 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" + glob "^8.0.1" + json-parse-even-better-errors "^2.3.1" + normalize-package-data "^4.0.0" + npm-normalize-package-bin "^1.0.1" 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" + resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz" integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== dependencies: read-package-json "^2.0.0" @@ -14428,15 +11030,15 @@ read-package-tree@^5.3.1: 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= + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz" + integrity sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw== 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" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" @@ -14445,8 +11047,8 @@ read-pkg-up@^7.0.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= + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz" + integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== dependencies: load-json-file "^4.0.0" normalize-package-data "^2.3.2" @@ -14454,7 +11056,7 @@ read-pkg@^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" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" @@ -14462,16 +11064,25 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@1, read@~1.0.1: +read@1, read@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= + resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz" + integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== 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: +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.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.1.4, readable-stream@~2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" @@ -14482,18 +11093,9 @@ read@1, read@~1.0.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.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" - -readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0, readdir-scoped-modules@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz" integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== dependencies: debuglog "^1.0.1" @@ -14501,203 +11103,158 @@ readdir-scoped-modules@^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" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" -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== + version "0.7.1" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== 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" + resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" 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== +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== dependencies: - hastscript "^5.0.0" - parse-entities "^1.1.2" - prismjs "~1.17.0" + regenerate "^1.4.2" -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: +regenerate@^1.4.2: version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -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-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -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== +regenerator-transform@^0.15.0: + version "0.15.0" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz" + integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== 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" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz" 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== +regexp-match-indices@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz" + integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== + dependencies: + regexp-tree "^0.1.11" + +regexp-tree@^0.1.11: + version "0.1.24" + resolved "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz" + integrity sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw== + +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" + functions-have-names "^1.2.2" -regexpp@^3.0.0, regexpp@^3.1.0: +regexpp@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" 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== +regexpu-core@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== 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" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" 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== + version "4.2.2" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz" + integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg== dependencies: - rc "^1.2.8" + 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" + resolved "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz" 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== +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== -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== +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== dependencies: jsesc "~0.5.0" -relateurl@0.2.x, relateurl@^0.2.7: +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= + resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== 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= + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz" + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== -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== +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== dependencies: css-select "^4.1.3" dom-converter "^0.2.0" htmlparser2 "^6.1.0" lodash "^4.17.21" - strip-ansi "^3.0.1" + strip-ansi "^6.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" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz" 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-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== request@2.88.0: version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" @@ -14721,105 +11278,81 @@ request@2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -request@2.88.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= + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + 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" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" 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= + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -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-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" 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" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" 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= + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve@^1.1.10, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, 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== +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.9.0: + version "1.22.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= +resolve@^2.0.0-next.3: + version "2.0.0-next.4" + resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== dependencies: - lowercase-keys "^1.0.0" + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^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= +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" + lowercase-keys "^2.0.0" restore-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: onetime "^5.1.0" @@ -14827,131 +11360,99 @@ restore-cursor@^3.1.0: ret@~0.1.10: version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz" 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= + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== reusify@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" 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" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" 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= + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz" + integrity sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ== 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== +robust-predicates@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz" + integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== rsvp@^4.8.4: version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.2.0, run-async@^2.4.0: +run-async@^2.4.0: version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" 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" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" 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= + resolved "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz" + integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== -rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.6.0, rxjs@^6.6.7: +rxjs@^6.4.0, rxjs@^6.6.0: version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz" 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== +rxjs@^7.5.5: + version "7.5.6" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" -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: +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" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 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= + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== dependencies: ret "~0.1.10" "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" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + resolved "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: "@cnakazawa/watch" "^1.0.3" @@ -14966,7 +11467,7 @@ sane@^4.0.3: sanitize-html@~2.5.3: version "2.5.3" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.5.3.tgz#91aa3dc760b072cdf92f9c6973747569b1ba1cd8" + resolved "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.5.3.tgz" integrity sha512-DGATXd1fs/Rm287/i5FBKVYSBBUL0iAaztOA1/RFhEs4yqo39/X52i/q/CwsfCUG5cilmXSBmnQmyWfnKhBlOg== dependencies: deepmerge "^4.2.2" @@ -14976,186 +11477,124 @@ sanitize-html@~2.5.3: 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@^3.1.9: - version "3.1.11" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" - saxes@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" 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" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" 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: +schema-utils@^2.6.5, schema-utils@^2.7.0: version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz" 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== +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== dependencies: - "@types/json-schema" "^7.0.7" + "@types/json-schema" "^7.0.8" 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= + resolved "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz" + integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - -semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= - -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-regex@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" - integrity sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ== - -"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: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.5, 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== +semver@7.3.4: + version "7.3.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + +semver@7.3.7, semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== 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: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" 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== +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== dependencies: debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" + 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 "~1.7.2" + http-errors "2.0.0" mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" + ms "2.1.3" + on-finished "2.4.1" range-parser "~1.2.1" - statuses "~1.5.0" - -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" + statuses "2.0.1" serialize-javascript@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz" 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" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" 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== +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.17.1" + send "0.18.0" -set-blocking@^2.0.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= + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== 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" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" @@ -15163,116 +11602,84 @@ set-value@^2.0.0, set-value@^2.0.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" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" 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" + resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" 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= + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== 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" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" 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= + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" 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" +shell-quote@^1.7.2: + version "1.7.3" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== 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== +shiki@^0.10.1: + version "0.10.1" + resolved "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz" + integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== dependencies: - json5 "^2.2.0" - onigasm "^2.2.5" + jsonc-parser "^3.0.0" + vscode-oniguruma "^1.6.1" 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" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" 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== +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== simple-concat@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" 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== + version "3.1.1" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== dependencies: decompress-response "^4.2.0" once "^1.3.1" @@ -15280,73 +11687,54 @@ simple-get@^3.0.3: 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= + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== 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= + resolved "https://registry.npmjs.org/simulate-event/-/simulate-event-1.4.0.tgz" + integrity sha512-2X/DaXEB9V4BQzavZ8bl15/D42Mtd2WBxRYJNGyQTIhE2uVFZqOCkF/FbY+oWiDNXh7hpFfpQ5gxwz6xYq0UAQ== dependencies: xtend "^4.0.1" +sirv@^1.0.7: + version "1.0.19" + resolved "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz" + integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== + dependencies: + "@polka/url" "^1.0.0-next.20" + mrmime "^1.0.0" + totalist "^1.0.0" + sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" 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" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" 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" - -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -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== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz" integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" @@ -15355,14 +11743,14 @@ snapdragon-node@^2.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" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz" 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" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz" integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" @@ -15374,35 +11762,26 @@ snapdragon@^0.8.1: 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, socks-proxy-agent@^6.1.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== +socks-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz" + integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== dependencies: agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" + debug "^4.3.3" + socks "^2.6.2" -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== +socks@^2.6.2: + version "2.7.0" + resolved "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz" + integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA== dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" + ip "^2.0.0" + smart-buffer "^4.2.0" sonic-boom@^1.0.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" + resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz" integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== dependencies: atomic-sleep "^1.0.0" @@ -15410,27 +11789,27 @@ sonic-boom@^1.0.2: 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= + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz" + integrity sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg== 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" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz" 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" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz" 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== +sort-package-json@~1.53.1: + version "1.53.1" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.53.1.tgz" + integrity sha512-ltLORrQuuPMpy23YkWCA8fO7zBOxM4P1j9LcGxci4K2Fk8jmSyCA/ATU6CFyy8qR2HQRx4RBYWzoi78FU/Anuw== dependencies: detect-indent "^6.0.0" detect-newline "3.1.0" @@ -15439,19 +11818,19 @@ sort-package-json@~1.44.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: +source-list-map@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz" 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-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 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" + resolved "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.0.2.tgz" integrity sha512-oX8d6ndRjN+tVyjj6PlXSyFPhDdVAPsZA30nD3/II8g4uOv8fCz0DMn5sy8KtVbDfKQxOpGwGJnK3xIW3tauDw== dependencies: data-urls "^2.0.0" @@ -15462,7 +11841,7 @@ source-map-loader@~1.0.2: 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" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: atob "^2.1.2" @@ -15471,49 +11850,37 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.4.18: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - -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== +source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 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" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: +source-map@^0.5.6: version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== 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" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" 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== +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== spdx-correct@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" @@ -15521,66 +11888,52 @@ spdx-correct@^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" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" 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" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" 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== +spdx-license-ids@^3.0.0: + version "3.0.11" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== 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" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz" 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" + resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz" integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== dependencies: readable-stream "^3.0.0" split@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz" 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= + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + version "1.17.0" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -15592,443 +11945,365 @@ sshpk@^1.7.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: +ssri@^8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== dependencies: minipass "^3.1.1" +ssri@^9.0.0, ssri@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz" + integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q== + 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" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz" 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, stack-utils@^2.0.3: +stack-utils@^2.0.2: version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz" 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= + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== dependencies: define-property "^0.2.5" object-copy "^0.1.0" -"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= +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +stdin@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz" + integrity sha512-2bacd1TXzqOEsqRa+eEWkRdOSznwptrs4gqFcpMq5tOtmJUGPZd10W5Lam6wQ4YQ/+qjQt4e9u35yXCF6mrlfQ== steno@^0.4.1: version "0.4.4" - resolved "https://registry.yarnpkg.com/steno/-/steno-0.4.4.tgz#071105bdfc286e6615c0403c27e9d7b5dcb855cb" - integrity sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs= + resolved "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz" + integrity sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w== 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-argv@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== - string-length@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" 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== +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" -"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== +string.prototype.matchall@^4.0.6: + version "4.0.7" + resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.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== +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" -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== +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" + define-properties "^1.1.4" + es-abstract "^1.19.5" -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== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" + safe-buffer "~5.2.0" -string_decoder@^1.0.0, string_decoder@^1.1.1, 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" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.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: +strip-ansi@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + 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= + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" 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= + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== 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" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" 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= + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== 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" + resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz" 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== +style-loader@~3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz" + integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + +style-mod@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz" + integrity sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw== + +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz" + integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== + +stylelint-config-prettier@^9.0.3: + version "9.0.3" + resolved "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.3.tgz" + integrity sha512-5n9gUDp/n5tTMCq1GLqSpA30w2sqWITSSEiAWQlpxkKGAUbjcemQ0nbkRvRUa0B1LgD3+hCvdL7B1eTxy1QHJg== + +stylelint-config-recommended@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz" + integrity sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ== + +stylelint-config-standard@^26.0.0: + version "26.0.0" + resolved "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-26.0.0.tgz" + integrity sha512-hUuB7LaaqM8abvkOO84wh5oYSkpXgTzHu2Zza6e7mY+aOmpNTjoFBRxSLlzY0uAOMWEFx0OMKzr+reG1BUtcqQ== dependencies: - loader-utils "^2.0.0" - schema-utils "^2.7.0" + stylelint-config-recommended "^8.0.0" -style-loader@~2.0.0: +stylelint-prettier@^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== + resolved "https://registry.npmjs.org/stylelint-prettier/-/stylelint-prettier-2.0.0.tgz" + integrity sha512-jvT3G+9lopkeB0ARmDPszyfaOnvnIF+30QCjZxyt7E6fynI1T9mOKgYDNb9bXX17M7PXMZaX3j/26wqakjp1tw== dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" + prettier-linter-helpers "^1.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= +stylelint@^14.9.1: + version "14.9.1" + resolved "https://registry.npmjs.org/stylelint/-/stylelint-14.9.1.tgz" + integrity sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA== + dependencies: + "@csstools/selector-specificity" "^2.0.1" + balanced-match "^2.0.0" + colord "^2.9.2" + cosmiconfig "^7.0.1" + css-functions-list "^3.1.0" + debug "^4.3.4" + execall "^2.0.0" + fast-glob "^3.2.11" + fastest-levenshtein "^1.0.12" + file-entry-cache "^6.0.1" + get-stdin "^8.0.0" + global-modules "^2.0.0" + globby "^11.1.0" + globjoin "^0.1.4" + html-tags "^3.2.0" + ignore "^5.2.0" + import-lazy "^4.0.0" + imurmurhash "^0.1.4" + is-plain-object "^5.0.0" + known-css-properties "^0.25.0" + mathml-tag-names "^2.1.3" + meow "^9.0.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.14" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^6.0.0" + postcss-selector-parser "^6.0.10" + 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 "^2.2.0" + svg-tags "^1.0.0" + table "^6.8.0" + v8-compile-cache "^2.3.0" + write-file-atomic "^4.0.1" supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 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" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8.0.0: version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: +supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz" integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" -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== +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -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" +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz" + integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== svgo-loader@^2.2.1: version "2.2.2" - resolved "https://registry.yarnpkg.com/svgo-loader/-/svgo-loader-2.2.2.tgz#5f54e3e0d77c36a84c42bcb42e812c4db534bf96" + resolved "https://registry.npmjs.org/svgo-loader/-/svgo-loader-2.2.2.tgz" 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== +svgo@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== 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" + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" -symbol-tree@^3.2.2, symbol-tree@^3.2.4: +symbol-tree@^3.2.4: version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" 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== + version "5.12.2" + resolved "https://registry.npmjs.org/systeminformation/-/systeminformation-5.12.2.tgz" + integrity sha512-j0Ix2l69jcoEerA9jAAr6CYWGKFbn1mB6Uw7m8xnOXs6XGvMKA4etZpsqyWnr8H/8SvVePzTae3y5CC8q+mC5w== -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== +table@^6.8.0: + version "6.8.0" + resolved "https://registry.npmjs.org/table/-/table-6.8.0.tgz" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== 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== + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar-stream@~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" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + 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" -tar@^6.0.2, tar@^6.1.0: +tar@^6.0.2, tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" @@ -16038,82 +12313,22 @@ tar@^6.0.2, tar@^6.1.0: 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== + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz" + integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== terminal-link@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz" integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== dependencies: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -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" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz" integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== dependencies: cacache "^15.0.5" @@ -16127,38 +12342,38 @@ terser-webpack-plugin@^4.1.0: 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== + version "5.3.3" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz" + integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== dependencies: - jest-worker "^27.0.2" - p-limit "^3.1.0" - schema-utils "^3.0.0" + "@jridgewell/trace-mapping" "^0.3.7" + jest-worker "^27.4.5" + schema-utils "^3.1.1" serialize-javascript "^6.0.0" - source-map "^0.6.1" - terser "^5.7.0" + terser "^5.7.2" -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== +terser@^4.6.3: + version "4.8.1" + resolved "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz" + integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== 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== +terser@^5.10.0, terser@^5.3.4, terser@^5.7.2: + version "5.14.2" + resolved "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" + source-map-support "~0.5.20" test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -16167,37 +12382,41 @@ test-exclude@^6.0.0: text-encoding@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" + resolved "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz" 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" + resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== -text-table@0.2.0, 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= + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" -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== +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" throat@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz" 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" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== dependencies: readable-stream "~2.3.6" @@ -16205,98 +12424,73 @@ through2@^2.0.0: through2@^4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz" 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.8, through@~2.3.6: +through@2, "through@>=2.2.7 <3", through@^2.3.4, 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" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -timers-ext@^0.1.7: +timers-ext@^0.1.5, timers-ext@^0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + resolved "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz" integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== dependencies: es5-ext "~0.10.46" next-tick "1" -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" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" -tmpl@1.0.x: +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +tmpl@1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" 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= + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== 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= + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== 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= + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz" + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== 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" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" 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" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz" integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" @@ -16305,49 +12499,32 @@ to-regex@^3.0.1, to-regex@^3.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== + version "1.2.0" + resolved "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.2.0.tgz" + integrity sha512-KsWUL8FccgBW9FPFm4vYoQbOOcO5m6hKOGYoXjbseD9/4Ft+ravXN5jolQ9kTKYcK4zPt1j+khx97GPGnVoi6A== 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.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + 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" + resolved "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz" integrity sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw== dependencies: commander "2" -tough-cookie@^2.3.3, 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" - -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== - dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" - punycode "^2.1.1" +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== tough-cookie@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz" integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: psl "^1.1.33" @@ -16356,54 +12533,37 @@ tough-cookie@^4.0.0: tough-cookie@~2.4.3: version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz" integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - tr46@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz" integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +treeverse@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/treeverse/-/treeverse-2.0.0.tgz" + integrity sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A== + trim-newlines@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" 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" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz" integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== dependencies: bs-logger "0.x" @@ -16417,118 +12577,117 @@ ts-jest@^26.3.0: 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== +ts-loader@^9.3.0: + version "9.3.1" + resolved "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz" + integrity sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw== dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" + chalk "^4.1.0" + enhanced-resolve "^5.0.0" micromatch "^4.0.0" - semver "^6.0.0" + semver "^7.3.4" -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== +tsconfig-paths@^3.9.0: + version "3.14.1" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" -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@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -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== +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@~2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== tsscmp@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" + resolved "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz" integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== -tsutils@^3.17.1: +tsutils@^3.21.0: version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" 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= + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== 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= + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== typanion@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/typanion/-/typanion-3.3.2.tgz#c31f3b2afb6e8ae74dbd3f96d5b1d8f9745e483e" - integrity sha512-m3v3wtFc6R0wtl0RpEn11bKXIOjS1zch5gmx0zg2G5qfGQ3A9TVZRMSL43O5eFuGXsrgzyvDcGRmSXGP5UqpDQ== + version "3.9.0" + resolved "https://registry.npmjs.org/typanion/-/typanion-3.9.0.tgz" + integrity sha512-7yPk67IIquhKQcUXOBM27vDuGmZf6oJbEmzgVfDniHCkT6+z4JnKY85nKqbstoec8Kp7hD06TP3Kc98ij43PIg== 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" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" 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= + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== 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" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" 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" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" 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" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz" 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" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" 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" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.17, type-is@~1.6.18: +type-is@~1.6.18: version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -16536,133 +12695,96 @@ type-is@~1.6.17, type-is@~1.6.18: type@^1.0.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + resolved "https://registry.npmjs.org/type/-/type-1.2.0.tgz" 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== +type@^2.5.0: + version "2.6.1" + resolved "https://registry.npmjs.org/type/-/type-2.6.1.tgz" + integrity sha512-OvgH5rB0XM+iDZGQ1Eg/o7IZn0XYJFVrN/9FQ4OWIYILyJJgVP2s1hLTOFn6UOZoDUI/HctGa0PFlE2n2HW3NQ== 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" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" 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= + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -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== +typedoc@~0.22.10: + version "0.22.18" + resolved "https://registry.npmjs.org/typedoc/-/typedoc-0.22.18.tgz" + integrity sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA== dependencies: - glob "^7.1.7" - handlebars "^4.7.7" - lodash "^4.17.21" + glob "^8.0.3" 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" + marked "^4.0.16" + minimatch "^5.1.0" + shiki "^0.10.1" -typescript@~4.1.3: - version "4.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.6.tgz#1becd85d77567c3c741172339e93ce2e69932138" - integrity sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow== +typescript@~4.7.3: + version "4.7.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== 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== + version "2.4.0" + resolved "https://registry.npmjs.org/typestyle/-/typestyle-2.4.0.tgz" + integrity sha512-/d1BL6Qi+YlMLEydnUEB8KL/CAjAN8cyt3/UyGnOyBrWf7bLGcR/6yhmsaUstO2IcYwZfagjE7AIzuI2vUW9mg== dependencies: - csstype "2.6.9" + csstype "3.0.10" 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" +uglify-js@^3.1.4: + version "3.17.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.0.tgz#55bd6e9d19ce5eef0d5ad17cd1f587d85b180a85" + integrity sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg== -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== +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" -unfetch@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== +underscore@>=1.3.1: + version "1.13.4" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz" + integrity sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ== -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-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -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== +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^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-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== -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== +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== union-value@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz" integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" @@ -16672,262 +12794,157 @@ union-value@^1.0.0: union@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" + resolved "https://registry.npmjs.org/union/-/union-0.5.0.tgz" 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" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz" 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" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz" 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" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== universalify@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" 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" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz" 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= + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== 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= + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz" + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== 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" + resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz" 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= +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" 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= + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== 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" + resolved "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz" + integrity sha512-c2H1fIgpUdwFRIru9HFno5DT73Ok8hg5oOb5AT3ayIgvCRfxgs2jyt5Slw8kEB7j3QUr6yJmMPDT/odjk7jXow== -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== +url-parse@~1.5.4: + version "1.5.10" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== 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" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz" 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= + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 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== + resolved "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz" + integrity sha512-K+5eQPYs14b3+E+hmE2J6gCZ4JmMl9DbYS6BeP2CHq6WMuNxErxf5B/n0fz85L8zUuoO6rIzNNmIQDu/j+1OcA== 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== +util@^0.10.3: + version "0.10.4" + resolved "https://registry.npmjs.org/util/-/util-0.10.4.tgz" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== 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= + resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== 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== + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3: +uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.0.0, uuid@^8.3.0: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0: +v8-compile-cache@2.3.0, v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" 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" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz" 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" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" @@ -16935,68 +12952,75 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: 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= + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz" + integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== dependencies: builtins "^1.0.3" +validate-npm-package-name@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz" + integrity sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q== + dependencies: + builtins "^5.0.0" + 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= + resolved "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz" + integrity sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg== 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= + resolved "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz" + integrity sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ== 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= + resolved "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz" + integrity sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA== 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= + resolved "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz" + integrity sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ== 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= + resolved "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz" + integrity sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg== -validator@13.6.0: - version "13.6.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.6.0.tgz#1e71899c14cdc7b2068463cb24c1cc16f6ec7059" - integrity sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg== +validator@13.7.0: + version "13.7.0" + resolved "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz" + 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= + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vega-canvas@^1.2.5: +vega-canvas@^1.2.5, vega-canvas@^1.2.6: version "1.2.6" - resolved "https://registry.yarnpkg.com/vega-canvas/-/vega-canvas-1.2.6.tgz#55e032ce9a62acd17229f6bac66d99db3d6879cd" + resolved "https://registry.npmjs.org/vega-canvas/-/vega-canvas-1.2.6.tgz" 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== +vega-crossfilter@~4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-4.1.0.tgz" + integrity sha512-aiOJcvVpiEDIu5uNc4Kf1hakkkPaVOO5fw5T4RSFAw6GEDbdqcB6eZ1xePcsLVic1hxYD5SGiUPdiiIs0SMh2g== dependencies: - d3-array "^2.7.1" + d3-array "^3.1.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" + resolved "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-5.7.4.tgz" integrity sha512-JGHTpUo8XGETH3b1V892we6hdjzCWB977ybycIu8DPqRoyrZuj6t1fCVImazfMgQD1LAfJlQybWP+alwKDpKig== dependencies: vega-format "^1.0.4" @@ -17004,128 +13028,122 @@ vega-dataflow@^5.7.3, vega-dataflow@^5.7.4, vega-dataflow@~5.7.4: 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== + version "6.21.0" + resolved "https://registry.npmjs.org/vega-embed/-/vega-embed-6.21.0.tgz" + integrity sha512-Tzo9VAfgNRb6XpxSFd7uphSeK2w5OxDY2wDtmpsQ+rQlPSEEI9TE6Jsb2nHRLD5J4FrmXKLrTcORqidsNQSXEg== dependencies: - fast-json-patch "^3.0.0-1" + fast-json-patch "^3.1.1" json-stringify-pretty-compact "^3.0.0" - semver "^7.3.5" - tslib "^2.2.0" + semver "^7.3.7" + tslib "^2.4.0" + vega-interpreter "^1.0.4" vega-schema-url-parser "^2.2.0" vega-themes "^2.10.0" - vega-tooltip "^0.25.1" + vega-tooltip "^0.28.0" -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== +vega-encode@~4.9.0: + version "4.9.0" + resolved "https://registry.npmjs.org/vega-encode/-/vega-encode-4.9.0.tgz" + integrity sha512-etv2BHuCn9bzEc0cxyA2TnbtcAFQGVFmsaqmB4sgBCaqTSEfXMoX68LK3yxBrsdm5LU+y3otJVoewi3qWYCx2g== dependencies: - d3-array "^2.7.1" - d3-interpolate "^2.0.1" + d3-array "^3.1.1" + d3-interpolate "^3.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" + resolved "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-3.0.0.tgz" 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" + resolved "https://registry.npmjs.org/vega-expression/-/vega-expression-5.0.0.tgz" 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== +vega-force@~4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/vega-force/-/vega-force-4.1.0.tgz" + integrity sha512-Sssf8iH48vYlz+E7/RpU+SUaJbuLoIL87U4tG2Av4gf/hRiImU49x2TI3EuhFWg1zpaCFxlz0CAaX++Oh/gjdw== dependencies: - d3-force "^2.1.1" + d3-force "^3.0.0" 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== +vega-format@^1.0.4, vega-format@^1.1.0, vega-format@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/vega-format/-/vega-format-1.1.0.tgz" + integrity sha512-6mgpeWw8yGdG0Zdi8aVkx5oUrpJGOpNxqazC2858RSDPvChM/jDFlgRMTYw52qk7cxU0L08ARp4BwmXaI75j0w== dependencies: - d3-array "^2.7.1" - d3-format "^2.0.0" - d3-time-format "^3.0.0" + d3-array "^3.1.1" + d3-format "^3.1.0" + d3-time-format "^4.1.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== +vega-functions@^5.12.1, vega-functions@^5.13.0, vega-functions@~5.13.0: + version "5.13.0" + resolved "https://registry.npmjs.org/vega-functions/-/vega-functions-5.13.0.tgz" + integrity sha512-Mf53zNyx+c9fFqagEI0T8zc9nMlx0zozOngr8oOpG1tZDKOgwOnUgN99zQKbLHjyv+UzWrq3LYTnSLyVe0ZmhQ== dependencies: - d3-array "^2.7.1" - d3-color "^2.0.0" - d3-geo "^2.0.1" + d3-array "^3.1.1" + d3-color "^3.0.1" + d3-geo "^3.0.1" vega-dataflow "^5.7.3" vega-expression "^5.0.0" - vega-scale "^7.1.1" + vega-scale "^7.2.0" vega-scenegraph "^4.9.3" vega-selections "^5.3.1" vega-statistics "^1.7.9" - vega-time "^2.0.4" + vega-time "^2.1.0" 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== +vega-geo@~4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/vega-geo/-/vega-geo-4.4.0.tgz" + integrity sha512-3YX41y+J5pu0PMjvBCASg0/lgvu9+QXWJZ+vl6FFKa8AlsIopQ67ZL7ObwqjZcoZMolJ4q0rc+ZO8aj1pXCYcw== dependencies: - d3-array "^2.7.1" - d3-color "^2.0.0" - d3-geo "^2.0.1" + d3-array "^3.1.1" + d3-color "^3.0.1" + d3-geo "^3.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== +vega-hierarchy@~4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-4.1.0.tgz" + integrity sha512-DWBK39IEt4FiQru12twzKSFUvFFZ7KtlH9+lAaqrJnKuIZFCyQ1XOUfKScfbKIlk4KS+DuCTNLI/pxC/f7Sk9Q== dependencies: - d3-hierarchy "^2.0.0" + d3-hierarchy "^3.1.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== +vega-interpreter@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-1.0.4.tgz" + integrity sha512-6tpYIa/pJz0cZo5fSxDSkZkAA51pID2LjOtQkOQvbzn+sJiCaWKPFhur8MBqbcmYZ9bnap1OYNwlrvpd2qBLvg== + +vega-label@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/vega-label/-/vega-label-1.2.0.tgz" + integrity sha512-1prOqkCAfXaUvMqavbGI0nbYGqV8UQR9qvuVwrPJ6Yxm3GIUIOA/JRqNY8eZR8USwMP/kzsqlfVEixj9+Y75VQ== dependencies: - vega-canvas "^1.2.5" + vega-canvas "^1.2.6" 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== + version "5.4.0" + resolved "https://registry.npmjs.org/vega-lite/-/vega-lite-5.4.0.tgz" + integrity sha512-e/P5iOtBE62WEWZhKP7sLcBd92YS9prfUQafelxoOeloooSSrkUwM/ZDmN5Q5ffByEZTiKfODtnwD6/xKDYUmw== dependencies: "@types/clone" "~2.1.1" array-flat-polyfill "^1.0.1" @@ -17133,26 +13151,26 @@ vega-lite@^5.1.0: 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" + tslib "~2.4.0" + vega-event-selector "~3.0.0" + vega-expression "~5.0.0" + vega-util "~1.17.0" + yargs "~17.5.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== +vega-loader@^4.3.2, vega-loader@^4.4.0, vega-loader@~4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/vega-loader/-/vega-loader-4.5.0.tgz" + integrity sha512-EkAyzbx0pCYxH3v3wghGVCaKINWxHfgbQ2pYDiYv0yo8e04S8Mv/IlRGTt6BAe7cLhrk1WZ4zh20QOppnGG05w== dependencies: - d3-dsv "^2.0.0" - node-fetch "^2.6.1" + d3-dsv "^3.0.1" + node-fetch "^2.6.7" topojson-client "^3.1.0" - vega-format "^1.0.4" + vega-format "^1.1.0" 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" + resolved "https://registry.npmjs.org/vega-parser/-/vega-parser-6.1.4.tgz" integrity sha512-tORdpWXiH/kkXcpNdbSVEvtaxBuuDtgYp9rBunVW9oLsjFvFXbSWlM1wvJ9ZFSaTfx6CqyTyGMiJemmr1QnTjQ== dependencies: vega-dataflow "^5.7.3" @@ -17161,161 +13179,157 @@ vega-parser@~6.1.4: 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== +vega-projection@^1.4.5, vega-projection@~1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/vega-projection/-/vega-projection-1.5.0.tgz" + integrity sha512-aob7qojh555x3hQWZ/tr8cIJNSWQbm6EoWTJaheZgFOY2x3cDa4Qrg3RJbGw6KwVj/IQk2p40paRzixKZ2kr+A== dependencies: - d3-geo "^2.0.1" - d3-geo-projection "^3.0.0" + d3-geo "^3.0.1" + d3-geo-projection "^4.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== +vega-regression@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/vega-regression/-/vega-regression-1.1.0.tgz" + integrity sha512-09K0RemY6cdaXBAyakDUNFfEkRcLkGjkDJyWQPAUqGK59hV2J+G3i4uxkZp18Vu0t8oqU7CgzwWim1s5uEpOcA== dependencies: - d3-array "^2.7.1" + d3-array "^3.1.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" + resolved "https://registry.npmjs.org/vega-runtime/-/vega-runtime-6.1.3.tgz" 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-scale@^7.0.3, vega-scale@^7.1.1, vega-scale@^7.2.0, vega-scale@~7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/vega-scale/-/vega-scale-7.2.0.tgz" + integrity sha512-QYltO/otrZHLrCGGf06Y99XtPtqWXITr6rw7rO9oL+l3d9o5RFl9sjHrVxiM7v+vGoZVWbBd5IPbFhPsXZ6+TA== + dependencies: + d3-array "^3.1.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + vega-time "^2.1.0" + vega-util "^1.17.0" + +vega-scenegraph@^4.10.0, vega-scenegraph@^4.9.2, vega-scenegraph@^4.9.3, vega-scenegraph@~4.10.1: + version "4.10.1" + resolved "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.10.1.tgz" + integrity sha512-takIpkmNxYHhJYALOYzhTin3EDzbys6U4g+l1yJZVlXG9YTdiCMuEVAdtaQOCqF9/7qytD6pCrMxJY2HaoN0qQ== + dependencies: + d3-path "^3.0.1" + d3-shape "^3.1.0" vega-canvas "^1.2.5" - vega-loader "^4.3.3" - vega-scale "^7.1.1" + vega-loader "^4.4.0" + vega-scale "^7.2.0" 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" + resolved "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-2.2.0.tgz" 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== + version "5.4.0" + resolved "https://registry.npmjs.org/vega-selections/-/vega-selections-5.4.0.tgz" + integrity sha512-Un3JdLDPjIpF9Dh4sw6m1c/QAcfam6m1YXHJ9vJxE/GdJ+sOrPxc7bcEU8VhOmTUN7IQUn4/1ry4JqqOVMbEhw== dependencies: + d3-array "3.1.1" 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== +vega-statistics@^1.7.9, vega-statistics@^1.8.0, vega-statistics@~1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/vega-statistics/-/vega-statistics-1.8.0.tgz" + integrity sha512-dl+LCRS6qS4jWDme/NEdPVt5r649uB4IK6Kyr2/czmGA5JqjuFmtQ9lHQOnRu8945XLkqLf+JIQQo7vnw+nslA== dependencies: - d3-array "^2.7.1" + d3-array "^3.1.1" vega-themes@^2.10.0: version "2.10.0" - resolved "https://registry.yarnpkg.com/vega-themes/-/vega-themes-2.10.0.tgz#82768b14686e3fbfbdab0e77cb63e12c62b4911e" + resolved "https://registry.npmjs.org/vega-themes/-/vega-themes-2.10.0.tgz" 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== +vega-time@^2.0.3, vega-time@^2.1.0, vega-time@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/vega-time/-/vega-time-2.1.0.tgz" + integrity sha512-Q9/l3S6Br1RPX5HZvyLD/cQ4K6K8DtpR09/1y7D66gxNorg2+HGzYZINH9nUvN3mxoXcBWg4cCUh3+JvmkDaEg== dependencies: - d3-array "^2.7.1" - d3-time "^2.0.0" + d3-array "^3.1.1" + d3-time "^3.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== +vega-tooltip@^0.28.0: + version "0.28.0" + resolved "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-0.28.0.tgz" + integrity sha512-DbK0V5zzk+p9cphZZXV91ZGeKq0zr6JIS0VndUoGTisldzw4tRgmpGQcTfMjew53o7/voeTM2ELTnJAJRzX4tg== dependencies: - vega-util "^1.16.0" + vega-util "^1.17.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== +vega-transforms@~4.10.0: + version "4.10.0" + resolved "https://registry.npmjs.org/vega-transforms/-/vega-transforms-4.10.0.tgz" + integrity sha512-Yk6ByzVq5F2niFfPlSsrU5wi+NZhsF7IBpJCcTfms4U7eoyNepUXagdFEJ3VWBD/Lit6GorLXFgO17NYcyS5gg== dependencies: - d3-array "^2.7.1" + d3-array "^3.1.1" vega-dataflow "^5.7.4" - vega-statistics "^1.7.9" - vega-time "^2.0.4" + vega-statistics "^1.8.0" + vega-time "^2.1.0" 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== + version "0.22.3" + resolved "https://registry.npmjs.org/vega-typings/-/vega-typings-0.22.3.tgz" + integrity sha512-PREcya3nXT9Tk7xU0IhEpOLVTlqizNtKXV55NhI6ApBjJtqVYbJL7IBh2ckKxGBy3YeUQ37BQZl56UqqiYVWBw== 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: +vega-util@^1.15.2, vega-util@^1.16.0, vega-util@^1.16.1, vega-util@^1.17.0, vega-util@~1.17.0: version "1.17.0" - resolved "https://registry.yarnpkg.com/vega-util/-/vega-util-1.17.0.tgz#b72ae0baa97f943bf591f8f5bb27ceadf06834ac" + resolved "https://registry.npmjs.org/vega-util/-/vega-util-1.17.0.tgz" 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" + resolved "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-4.5.8.tgz" 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== +vega-view@~5.11.0: + version "5.11.0" + resolved "https://registry.npmjs.org/vega-view/-/vega-view-5.11.0.tgz" + integrity sha512-MI9NTRFmtFX6ADk6KOHhi8bhHjC9pPm42Bj2+74c6l1d3NQZf9Jv7lkiGqKohdkQDNH9LPwz/6slhKwPU9JdkQ== dependencies: - d3-array "^2.7.1" - d3-timer "^2.0.0" + d3-array "^3.1.1" + d3-timer "^3.0.1" vega-dataflow "^5.7.3" - vega-format "^1.0.4" - vega-functions "^5.10.0" + vega-format "^1.1.0" + vega-functions "^5.13.0" vega-runtime "^6.1.3" - vega-scenegraph "^4.9.4" + vega-scenegraph "^4.10.0" 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== +vega-voronoi@~4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-4.2.0.tgz" + integrity sha512-1iuNAVZgUHRlBpdq4gSga3KlQmrgFfwy+KpyDgPLQ8HbLkhcVeT7RDh2L6naluqD7Op0xVLms3clR920WsYryQ== dependencies: - d3-delaunay "^5.3.0" + d3-delaunay "^6.0.2" 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" + resolved "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-4.1.3.tgz" integrity sha512-is4zYn9FMAyp9T4SAcz2P/U/wqc0Lx3P5YtpWKCbOH02a05vHjUQrQ2TTPOuvmMfAEDCSKvbMSQIJMOE018lJA== dependencies: vega-canvas "^1.2.5" @@ -17325,411 +13339,329 @@ vega-wordcloud@~4.1.3: 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== + version "5.22.1" + resolved "https://registry.npmjs.org/vega/-/vega-5.22.1.tgz" + integrity sha512-KJBI7OWSzpfCPbmWl3GQCqBqbf2TIdpWS0mzO6MmWbvdMhWHf74P9IVnx1B1mhg0ZTqWFualx9ZYhWzMMwudaQ== dependencies: - vega-crossfilter "~4.0.5" + vega-crossfilter "~4.1.0" vega-dataflow "~5.7.4" - vega-encode "~4.8.3" + vega-encode "~4.9.0" 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-force "~4.1.0" + vega-format "~1.1.0" + vega-functions "~5.13.0" + vega-geo "~4.4.0" + vega-hierarchy "~4.1.0" + vega-label "~1.2.0" + vega-loader "~4.5.0" vega-parser "~6.1.4" - vega-projection "~1.4.5" - vega-regression "~1.0.9" + vega-projection "~1.5.0" + vega-regression "~1.1.0" 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-scale "~7.2.0" + vega-scenegraph "~4.10.1" + vega-statistics "~1.8.0" + vega-time "~2.1.0" + vega-transforms "~4.10.0" vega-typings "~0.22.0" vega-util "~1.17.0" - vega-view "~5.10.1" + vega-view "~5.11.0" vega-view-transforms "~4.5.8" - vega-voronoi "~4.1.5" + vega-voronoi "~4.2.0" vega-wordcloud "~4.1.3" -verdaccio-audit@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/verdaccio-audit/-/verdaccio-audit-10.0.0.tgz#d3304d923c7f2c28c173a02425208c941f25217b" - integrity sha512-Epsh+C7ZEdq39PR9QeDBTWktbeqc0zOQjMzWte6Ut5Jh6fPLZzxGF8VK8O67B6mnTwLvGy50A1aPVM97Ysh5Rw== +verdaccio-audit@10.2.2: + version "10.2.2" + resolved "https://registry.npmjs.org/verdaccio-audit/-/verdaccio-audit-10.2.2.tgz" + integrity sha512-f2uZlKD7vi0yEB0wN8WOf+eA/3SCyKD9cvK17Hh7Wm8f/bl7k1B3hHOTtUCn/yu85DGsj2pcNzrAfp2wMVgz9Q== dependencies: - express "4.17.1" - request "2.88.2" + body-parser "1.20.0" + express "4.18.1" + https-proxy-agent "5.0.1" + node-fetch "2.6.7" -verdaccio-htpasswd@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/verdaccio-htpasswd/-/verdaccio-htpasswd-10.0.0.tgz#7a7f44e8ed4db40c53deef0f5101f2a16dce4ff1" - integrity sha512-3TKwiLwl8/fbaTDawHvjSYcsyMmdARg58keP/1plv74x+Jw0sC66HbbRwQ/tPO5mqoG0UwoWW+lkO8h/OiWi9w== +verdaccio-htpasswd@10.5.0: + version "10.5.0" + resolved "https://registry.npmjs.org/verdaccio-htpasswd/-/verdaccio-htpasswd-10.5.0.tgz" + integrity sha512-olBsT3uy1TT2ZqmMCJUsMHrztJzoEpa8pxxvYrDZdWnEksl6mHV10lTeLbH9BUwbEheOeKkkdsERqUOs+if0jg== dependencies: - "@verdaccio/file-locking" "^10.0.0" - apache-md5 "1.1.2" + "@verdaccio/file-locking" "10.3.0" + apache-md5 "1.1.7" bcryptjs "2.4.3" - http-errors "1.8.0" + http-errors "2.0.0" unix-crypt-td-js "1.1.4" -verdaccio@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/verdaccio/-/verdaccio-5.1.1.tgz#83c1893ede39e9ad181b2c5822a3ca1d683ad5cd" - integrity sha512-jLuBgykjMGS+kOI0cU16DqF/skSBlRUdAaArjXj20o3N/bnzhrLQRjEBCaXqoDMhlPR3RaY1kz3fWxNJQ4Anug== - dependencies: - "@verdaccio/commons-api" "10.0.0" - "@verdaccio/local-storage" "10.0.6" - "@verdaccio/readme" "10.0.0" - "@verdaccio/streams" "10.0.0" - "@verdaccio/ui-theme" "3.1.0" +verdaccio@^5.13.3: + version "5.14.0" + resolved "https://registry.npmjs.org/verdaccio/-/verdaccio-5.14.0.tgz" + integrity sha512-++YTBxeUvBcsZb3e77x2lH+bdg5xrETi7h+5xtd2KPHrcW+MlpwCWDcwyHdCVZ7LhOgkzSSJD9L/0i1BkbwB8Q== + dependencies: + "@verdaccio/commons-api" "10.2.0" + "@verdaccio/local-storage" "10.3.1" + "@verdaccio/readme" "10.4.1" + "@verdaccio/streams" "10.2.0" + "@verdaccio/ui-theme" "6.0.0-6-next.25" JSONStream "1.3.5" - async "3.2.0" - body-parser "1.19.0" - clipanion "3.0.0-rc.12" + async "3.2.4" + body-parser "1.20.0" + clipanion "3.1.0" compression "1.7.4" cookies "0.8.0" cors "2.8.5" - dayjs "1.10.4" - debug "^4.3.1" + dayjs "1.11.3" + debug "^4.3.3" envinfo "7.8.1" - eslint-import-resolver-node "0.3.4" - express "4.17.1" - fast-safe-stringify "^2.0.7" + eslint-import-resolver-node "0.3.6" + express "4.18.1" + express-rate-limit "5.5.1" + fast-safe-stringify "2.1.1" handlebars "4.7.7" - http-errors "1.8.0" + http-errors "2.0.0" js-yaml "4.1.0" jsonwebtoken "8.5.1" - kleur "4.1.4" + kleur "4.1.5" lodash "4.17.21" - lru-cache "6.0.0" + lru-cache "7.13.1" lunr-mutable-indexes "2.3.2" - marked "2.0.5" + marked "4.0.18" memoizee "0.4.15" - mime "2.5.2" - minimatch "3.0.4" + mime "3.0.0" + minimatch "5.1.0" mkdirp "1.0.4" mv "2.1.1" - pino "6.11.3" + pino "6.14.0" pkginfo "0.4.1" prettier-bytes "^1.0.4" - pretty-ms "^5.0.0" + pretty-ms "^7.0.1" request "2.88.0" - semver "7.3.5" - validator "13.6.0" - verdaccio-audit "10.0.0" - verdaccio-htpasswd "10.0.0" + semver "7.3.7" + validator "13.7.0" + verdaccio-audit "10.2.2" + verdaccio-htpasswd "10.5.0" verror@1.10.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== 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-jsonrpc@8.0.2, vscode-jsonrpc@^8.0.2: + version "8.0.2" + resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz" + integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ== + +vscode-jsonrpc@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz" + integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== + +vscode-languageserver-protocol@^3.17.0: + version "3.17.2" + resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz" + integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg== + dependencies: + vscode-jsonrpc "8.0.2" + vscode-languageserver-types "3.17.2" + +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== + +vscode-oniguruma@^1.6.1: + version "1.6.2" + resolved "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz" + integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA== vscode-textmate@5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" + resolved "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz" integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== -w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: +vscode-ws-jsonrpc@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/vscode-ws-jsonrpc/-/vscode-ws-jsonrpc-1.0.2.tgz" + integrity sha512-09OpRC0RcqZs4DleJRgs+R+7gQkwb4tgvsL43lzVZwW4N5NO3H/9sLNeKPBt83k7WyA8qBZjrzM6X7tKFpFrjQ== + dependencies: + vscode-jsonrpc "^8.0.2" + +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" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: browser-process-hrtime "^1.0.0" -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== - dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" - xml-name-validator "^3.0.0" +w3c-keyname@^2.2.4: + version "2.2.5" + resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.5.tgz" + integrity sha512-WJrK7i6w+ULuZsGscCezbCH4Aev5U3xY87vnSimzzEgPQhb0Sa0a1rE3c2jtEwrFtSfi61Jefw3jI5/DD/3jbQ== w3c-xmlserializer@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz" 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" +walk-up-path@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz" + integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg== -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== +walker@^1.0.7, walker@~1.0.5: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" + makeerror "1.0.12" -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== +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -wcwidth@^1.0.0: +wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: defaults "^1.0.3" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + 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" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz" 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" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz" 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== +webpack-bundle-analyzer@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz" + integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ== 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" + 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" -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== +webpack-cli@^4.9.2: + version "4.10.0" + resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== 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" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" commander "^7.0.0" - execa "^5.0.0" + cross-spawn "^7.0.3" 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: +webpack-merge@^5.7.3, webpack-merge@^5.8.0: version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz" 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: +webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.4.3: version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz" 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-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -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" +webpack@^5.72.0: + version "5.74.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz" + integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== + 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.4.1" + acorn "^8.7.1" + acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.0" - es-module-lexer "^0.7.1" + 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.4" - json-parse-better-errors "^1.0.2" + 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.0.0" + schema-utils "^3.1.0" tapable "^2.1.1" terser-webpack-plugin "^5.1.3" - watchpack "^2.2.0" - webpack-sources "^2.3.0" + watchpack "^2.4.0" + webpack-sources "^3.2.3" -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: +whatwg-encoding@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" 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" + resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz" integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== -whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: +whatwg-mimetype@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + 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" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== dependencies: lodash "^4.7.0" @@ -17738,7 +13670,7 @@ whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.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" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: is-bigint "^1.0.1" @@ -17749,95 +13681,56 @@ which-boxed-primitive@^1.0.2: 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-pm-runs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" - integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== which@^1.2.9, which@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" 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" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" 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== +wide-align@^1.1.2, wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: - string-width "^4.0.0" + string-width "^1.0.2 || 2 || 3 || 4" wildcard@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" 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" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== worker-loader@^3.0.2: version "3.0.8" - resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-3.0.8.tgz#5fc5cda4a3d3163d9c274a4e3a811ce8b60dbb37" + resolved "https://registry.npmjs.org/worker-loader/-/worker-loader-3.0.8.tgz" 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" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" @@ -17846,7 +13739,7 @@ wrap-ansi@^6.2.0: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -17855,21 +13748,21 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 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" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz" 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: +write-file-atomic@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: imurmurhash "^0.1.4" @@ -17877,9 +13770,17 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.0, write-file-atomic@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz" + integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + 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" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz" integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== dependencies: detect-indent "^5.0.0" @@ -17891,7 +13792,7 @@ write-json-file@^3.2.0: 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" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz" integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== dependencies: detect-indent "^6.0.0" @@ -17903,107 +13804,81 @@ write-json-file@^4.3.0: write-pkg@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" + resolved "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz" 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: +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.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== +ws@^7.3.1, ws@^7.4.6: + version "7.5.9" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== 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" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" 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= + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== -xmlchars@^2.1.1, xmlchars@^2.2.0: +xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" 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: +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" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xterm-addon-fit@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.4.0.tgz#06e0c5d0a6aaacfb009ef565efa1c81e93d90193" - integrity sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w== +xterm-addon-fit@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz" + integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ== -xterm@~4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" - integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== +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== +y-codemirror.next@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/y-codemirror.next/-/y-codemirror.next-0.3.2.tgz" + integrity sha512-3ksMXoietzNkrgluG9ut+5q4PNHCS6sQ+mHd44hNX1s7TBe4iDgOOIswfY3oLsdamZLAUPr+TnRdYgYuNDs7Qg== 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== + version "0.1.1" + resolved "https://registry.yarnpkg.com/y-leveldb/-/y-leveldb-0.1.1.tgz#c2c35bc2b12a6c195b807a127c56c7c5a50cc610" + integrity sha512-L8Q0MQmxCQ0qWIOuPzLbWn95TNhrCI7M6LaHnilU4I2IX08e4Dmfg5Tgy4JZ3tnl2aiuZyDOJplHl/msIB/IsA== 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" + resolved "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.5.tgz" integrity sha512-Wil92b7cGk712lRHDqS4T90IczF6RkcvCwAD0A2OPg+adKmOe+nOiT/N2hvpQIWS3zfjmtL4CPaH5sIW1Hkm/A== dependencies: lib0 "^0.2.42" y-websocket@^1.3.15: - version "1.3.16" - resolved "https://registry.yarnpkg.com/y-websocket/-/y-websocket-1.3.16.tgz#0ec1a141d593933dfbfba2fb9fa9d95dca332c89" - integrity sha512-538dwNOQeZCpMfhh67y40goxHQZKubjoXtfhQieUF2bIQfHVV44bGFeAiYiBHgwOSRdwp7qG4MmDwU0M3U3vng== + version "1.4.3" + resolved "https://registry.npmjs.org/y-websocket/-/y-websocket-1.4.3.tgz" + integrity sha512-VobyJaAoyWIETETNZragnTpL7kcJr8a/CIUQP6DfXcQ4v0UmZUuANdsPsbmMjDsEeUECVFRhHauxpDtRhYqkaQ== dependencies: lib0 "^0.2.42" lodash.debounce "^4.0.8" @@ -18012,70 +13887,52 @@ y-websocket@^1.3.15: 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" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" 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" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" 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" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0, yaml@^1.7.2: +yaml@^1.10.0: version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" 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" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.7: +yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^18.1.2, yargs-parser@^18.1.3: +yargs-parser@21.0.1, yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + +yargs-parser@^18.1.2: version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" 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" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" @@ -18092,7 +13949,7 @@ yargs@^15.4.1: yargs@^16.2.0: version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -18103,56 +13960,42 @@ yargs@^16.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== +yargs@^17.4.0, yargs@~17.5.1: + version "17.5.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== 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" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" -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== +yarn-deduplicate@^5.0.0: + version "5.0.2" + resolved "https://registry.npmjs.org/yarn-deduplicate/-/yarn-deduplicate-5.0.2.tgz" + integrity sha512-pxKa+dM7DMQ4X2vYLKqGCUgtEoTtdMVk9gNoIsxsMSP0rOV51IWFcKHfRIcZjAPNgHTrxz46sKB4xr7Nte7jdw== 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== - -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" + commander "^9.4.0" + semver "^7.3.7" + tslib "^2.4.0" -yazl@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" - integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== - dependencies: - buffer-crc32 "~0.2.3" +yarn@1.22.19: + version "1.22.19" + resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz" + integrity sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ== -yjs@^13.5.17: - version "13.5.17" - resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.5.17.tgz#888830e015cce709f3413f78cfdcf3c2176d4b0a" - integrity sha512-EeroWadB+/SlGuNwXaIjo75QlTlCjst3U/dLqhTkqwIXeCGl/nRTbQev+iYgWZVskD1eTCvaDc2FdrGdpKq32A== +yjs@^13.5.34: + version "13.5.41" + resolved "https://registry.npmjs.org/yjs/-/yjs-13.5.41.tgz" + integrity sha512-4eSTrrs8OeI0heXKKioRY4ag7V5Bk85Z4MeniUyown3o3y0G7G4JpAZWrZWfTp7pzw2b53GkAQWKqHsHi9j9JA== dependencies: - lib0 "^0.2.42" + 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" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==