diff --git a/.eslintignore b/.eslintignore index 28e231e712..514583fc1e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,7 +6,7 @@ **/build **/cypress/fixtures **/dist -**/dist-test +**/dist-* **/node_modules **/support/fixtures/* !**/support/fixtures/projects @@ -22,11 +22,14 @@ system-tests/projects/**/static/* system-tests/projects/**/*.jsx system-tests/projects/**/fail.js system-tests/lib/scaffold/plugins/index.js -system-tests/lib/scaffold/support/index.js +system-tests/lib/scaffold/support/e2e.js +system-tests/lib/scaffold/support/component.js system-tests/lib/scaffold/support/commands.js system-tests/test/support/projects/e2e/cypress/ -system-tests/projects/e2e/cypress/integration/stdout_exit_early_failing_spec.js -system-tests/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts +system-tests/projects/e2e/cypress/e2e/stdout_exit_early_failing.cy.js +system-tests/projects/e2e/cypress/e2e/typescript_syntax_error.cy.ts +system-tests/projects/config-with-ts-syntax-error/** +system-tests/projects/config-with-ts-module-error/** **/test/fixtures @@ -35,14 +38,20 @@ system-tests/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts # cli/types is linted by tslint/dtslint cli/types +# cli/react, cli/vue, and cli/mount-utils are all copied from dist'd builds +cli/react +cli/vue +cli/vue2 +cli/mount-utils + # packages/example is not linted (think about changing this) packages/example packages/extension/test/helpers/background.js -integration/stdout_exit_early_failing_spec.js +e2e/stdout_exit_early_failing_spec.js npm/webpack-preprocessor/cypress/tests/e2e/compile-error.js -npm/webpack-preprocessor/examples/use-babelrc/cypress/integration/spec.js +npm/webpack-preprocessor/examples/use-babelrc/cypress/e2e/spec.cy.js npm/cypress-schematic/src/**/*.js @@ -60,3 +69,41 @@ npm/cypress-schematic/src/**/*.js **/.next/** /npm/create-cypress-tests/initial-template /npm/create-cypress-tests/**/*.template.* + +# The global eslint configuration is not set up to parse vue@2 files +/npm/vue2/**/*.vue + +packages/data-context/test/unit/codegen/files + +# community templates we test against, no need to lint +system-tests/projects/cra-4/**/* +system-tests/projects/cra-5/**/* +system-tests/projects/cra-ejected/**/* +system-tests/projects/create-react-app-configured/**/* +system-tests/projects/create-react-app-unconfigured/**/* +system-tests/projects/create-react-app-custom-index-html + +system-tests/projects/vueclivue2-unconfigured/**/* +system-tests/projects/vueclivue2-configured/**/* + +system-tests/projects/vueclivue3-unconfigured/**/* +system-tests/projects/vueclivue3-configured/**/* +system-tests/projects/vueclivue3-custom-index-html + +system-tests/projects/vuecli5vue3-unconfigured/**/* +system-tests/projects/vuecli5vue3-configured/**/* + +system-tests/projects/vue3-vite-ts-unconfigured/**/* +system-tests/projects/vue3-vite-ts-configured/**/* +system-tests/projects/vue3-vite-ts-custom-index-html + +system-tests/projects/nextjs-unconfigured/**/* +system-tests/projects/nextjs-configured/**/* + +system-tests/projects/nuxtjs-vue2-unconfigured/**/* +system-tests/projects/nuxtjs-vue2-configured/**/* + +system-tests/projects/react-app-webpack-5-unconfigured/**/* + +system-tests/project-fixtures/** +system-tests/projects/**/*/expected-cypress*/**/* diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..8524110532 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,71 @@ +const fs = require('fs') +const path = require('path') +const { specifiedRules } = require('graphql') + +const graphqlOpts = { + env: 'literal', + tagName: 'gql', + schemaString: fs.readFileSync( + path.join(__dirname, 'packages/graphql/schemas/schema.graphql'), + 'utf8', + ), +} + +const validators = specifiedRules +.map((rule) => rule.name) +.filter( + (ruleName) => { + return [ + 'NoUnusedFragmentsRule', + 'KnownFragmentNamesRule', + 'NoUnusedVariablesRule', + ].findIndex((x) => x === ruleName) === -1 + }, +) + +module.exports = { + plugins: [ + '@cypress/dev', + 'graphql', + ], + extends: [ + 'plugin:@cypress/dev/general', + 'plugin:@cypress/dev/tests', + ], + parser: '@typescript-eslint/parser', + rules: { + 'no-duplicate-imports': 'off', + 'import/no-duplicates': 'off', + '@typescript-eslint/no-duplicate-imports': [ + 'error', + ], + 'prefer-spread': 'off', + 'prefer-rest-params': 'off', + 'no-useless-constructor': 'off', + 'no-restricted-properties': [ + 'error', + { + object: 'process', + property: 'geteuid', + message: 'process.geteuid() will throw on Windows. Do not use it unless you catch any potential errors.', + }, + { + object: 'os', + property: 'userInfo', + message: 'os.userInfo() will throw when there is not an `/etc/passwd` entry for the current user (like when running with --user 12345 in Docker). Do not use it unless you catch any potential errors.', + }, + ], + 'graphql/capitalized-type-name': ['warn', graphqlOpts], + 'graphql/no-deprecated-fields': ['error', graphqlOpts], + 'graphql/template-strings': ['error', { ...graphqlOpts, validators }], + 'graphql/required-fields': [ + 'error', + { ...graphqlOpts, requiredFields: ['id'] }, + ], + }, + settings: { + react: { + version: '16.8', + }, + }, +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 91bb4cfa7e..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "plugins": [ - "@cypress/dev" - ], - "extends": [ - "plugin:@cypress/dev/general", - "plugin:@cypress/dev/tests" - ], - "rules": { - "prefer-spread": "off", - "prefer-rest-params": "off", - "no-useless-constructor": "off", - "no-restricted-properties": [ - "error", - { - "object": "process", - "property": "geteuid", - "message": "process.geteuid() will throw on Windows. Do not use it unless you catch any potential errors." - }, - { - "object": "os", - "property": "userInfo", - "message": "os.userInfo() will throw when there is not an `/etc/passwd` entry for the current user (like when running with --user 12345 in Docker). Do not use it unless you catch any potential errors." - } - ] - }, - "settings": { - "react": { - "version": "16.8" - } - } -} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5ca29eefa5..b2a8d86544 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -34,6 +34,8 @@ /packages/net-stubbing/ @cypress-io/end-to-end /packages/network/ @cypress-io/end-to-end /packages/proxy/ @cypress-io/end-to-end +/packages/data-context/ @tgriesser +/packages/graphql/ @tgriesser /packages/reporter/ @cypress-io/end-to-end /packages/resolve-dist/ @cypress-io/end-to-end /packages/rewriter/ @cypress-io/end-to-end diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9f079c1adb..34771c09ed 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -35,4 +35,3 @@ DO NOT DELETE the PR checklist. - [ ] Has the original issue (or this PR, if no issue exists) been tagged with a release in ZenHub? (user-facing changes only) - [ ] Has a PR for user-facing changes been opened in [`cypress-documentation`](https://github.com/cypress-io/cypress-documentation)? - [ ] Have API changes been updated in the [`type definitions`](https://github.com/cypress-io/cypress/blob/develop/cli/types/cypress.d.ts)? -- [ ] Have new configuration options been added to the [`cypress.schema.json`](https://github.com/cypress-io/cypress/blob/develop/cli/schema/cypress.schema.json)? diff --git a/.gitignore b/.gitignore index 8634a7f20d..296541ed04 100644 --- a/.gitignore +++ b/.gitignore @@ -9,22 +9,18 @@ _test-output cypress.zip .babel-cache +# from config, compiled .js files +packages/config/src/*.js + # from extension Cached Theme.pak Cached Theme Material Design.pak -# from config, compiled .js files -packages/config/lib/*.js - # from data-context, compiled .js files packages/data-context/src/**/*.js packages/errors/src/**/*.js packages/errors/test/**/*.js -# from desktop-gui -packages/desktop-gui/cypress/videos -packages/desktop-gui/src/jsconfig.json - # from driver packages/driver/cypress/videos packages/driver/cypress/screenshots @@ -72,6 +68,7 @@ packages/socket/lib/*.js system-tests/.projects system-tests/.http-mitm-proxy system-tests/fixtures/large-img +system-tests/lib/fixtureDirs.ts # from npm/react /npm/react/bin/* @@ -83,6 +80,9 @@ system-tests/fixtures/large-img /npm/design-system/cypress/videos /npm/design-system/.babel-cache +# from npm/webpack-dev-server-fresh +/npm/webpack-dev-server-fresh/cypress/videos + # from runner-ct /packages/runner-ct/cypress/screenshots @@ -94,6 +94,8 @@ system-tests/fixtures/large-img # graphql, auto-generated /packages/launchpad/src/generated /packages/app/src/generated +/packages/frontend-shared/src/generated +/packages/frontend-shared/cypress/e2e/support/e2eProjectDirs.ts # from npm/create-cypress-tests /npm/create-cypress-tests/initial-template @@ -104,7 +106,6 @@ scripts/support binary-url.json # Allows us to dynamically create eslint rules that override the default for Decaffeinate scripts -.eslintrc.js cli/visual-snapshots # Created by https://www.gitignore.io/api/osx,git,node,windows,intellij,linux diff --git a/.releaserc.base.js b/.releaserc.base.js index 0c6ed7443b..95f6bbf940 100644 --- a/.releaserc.base.js +++ b/.releaserc.base.js @@ -15,5 +15,6 @@ module.exports = { ], extends: 'semantic-release-monorepo', branches: [ + 'master', ], } diff --git a/.vscode/cspell.json b/.vscode/cspell.json index b742f5475d..d85704b9ed 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -15,6 +15,7 @@ "OVERLIMIT", "Pinia", "pnpm", + "pseudoclass", "Screenshotting", "shiki", "testid", @@ -25,7 +26,8 @@ "urql", "vite", "vitejs", - "vueuse" + "vueuse", + "Windi" ], "ignoreWords": [], "import": [] diff --git a/.vscode/terminals.json b/.vscode/terminals.json index 27f9a82ccf..e154b4233b 100644 --- a/.vscode/terminals.json +++ b/.vscode/terminals.json @@ -39,6 +39,27 @@ "cwd": "[cwd]/system-tests", "command": "yarn test [fileBasename]" }, + { + "name": "packages/app cypress open", + "focus": true, + "onlySingle": true, + "cwd": "[cwd]/packages/app", + "command": "yarn cypress:open" + }, + { + "name": "packages/app dev", + "focus": true, + "onlySingle": true, + "cwd": "[cwd]/packages/app", + "command": "yarn dev" + }, + { + "name": "packages/app watch", + "focus": true, + "onlySingle": true, + "cwd": "[cwd]", + "command": "yarn watch" + }, { "name": "packages/server test-watch", "focus": true, @@ -75,20 +96,6 @@ "onlySingle": true, "cwd": "[cwd]/packages/driver", "command": "yarn cypress:open" - }, - { - "name": "packages/desktop-gui cypress open", - "focus": true, - "onlySingle": true, - "cwd": "[cwd]/packages/desktop-gui", - "command": "yarn cypress:open" - }, - { - "name": "packages/desktop-gui watch", - "focus": true, - "onlySingle": true, - "cwd": "[cwd]/packages/desktop-gui", - "command": "yarn watch" } ] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c122f5ef1..306512f9e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -259,7 +259,6 @@ Here is a list of the core packages in this repository with a short description, | Folder Name | Package Name | Purpose | | :------------------------------------ | :---------------------- | :--------------------------------------------------------------------------- | | [cli](./cli) | `cypress` | The command-line tool that is packaged as an `npm` module. | - | [desktop-gui](./packages/desktop-gui) | `@packages/desktop-gui` | The front-end code for the Cypress Desktop GUI. | | [driver](./packages/driver) | `@packages/driver` | The code that is used to drive the behavior of the API commands. | | [electron](./packages/electron) | `@packages/electron` | The Cypress implementation of Electron. | | [example](./packages/example) | `@packages/example` | Our example kitchen-sink application. | diff --git a/apollo.config.js b/apollo.config.js new file mode 100644 index 0000000000..b575e16526 --- /dev/null +++ b/apollo.config.js @@ -0,0 +1,14 @@ +const path = require('path') + +// For use with Apollo Extension for VSCode: +// https://www.apollographql.com/docs/devtools/editor-plugins/ +module.exports = { + client: { + service: { + name: 'cypress-io', + localSchemaFile: path.join(__dirname, 'packages/graphql/schemas/schema.graphql'), + }, + tagName: 'gql', + includes: [path.join(__dirname, 'packages/{launchpad,app,frontend-shared}/src/**/*.{vue,ts,js,tsx,jsx}')], + }, +} diff --git a/autobarrel.json b/autobarrel.json new file mode 100644 index 0000000000..0d09bcb0fd --- /dev/null +++ b/autobarrel.json @@ -0,0 +1,14 @@ +{ + "prefix": "/* eslint-disable padding-line-between-statements */", + "paths": [ + "packages/graphql/src/**/*", + "packages/data-context/src/**/*", + "packages/scaffold-config/src/**" + ], + "ignore": [ + "packages/data-context/src/gen", + "packages/graphql/src/stitching", + "packages/graphql/src/testing", + "packages/graphql/src/gen" + ] +} \ No newline at end of file diff --git a/circle.yml b/circle.yml index 263ffb9f55..c275c0990f 100644 --- a/circle.yml +++ b/circle.yml @@ -29,7 +29,7 @@ mainBuildFilters: &mainBuildFilters only: - develop - 10.0-release - - unify-1449-beta-slug-length + - unify-1449-check-path-length-in-build # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -38,7 +38,8 @@ macWorkflowFilters: &mac-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ unify-1449-beta-slug-length, << pipeline.git.branch >> ] + - equal: [ '10.0-release', << pipeline.git.branch >> ] + - equal: [ unify-1449-check-path-length-in-build, << pipeline.git.branch >> ] - matches: pattern: "-release$" value: << pipeline.git.branch >> @@ -46,9 +47,9 @@ macWorkflowFilters: &mac-workflow-filters windowsWorkflowFilters: &windows-workflow-filters when: or: - - equal: [ master, << pipeline.git.branch >> ] - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ unify-1449-beta-slug-length, << pipeline.git.branch >> ] + - equal: [ '10.0-release', << pipeline.git.branch >> ] + - equal: [ unify-1449-check-path-length-in-build, << pipeline.git.branch >> ] - matches: pattern: "-release$" value: << pipeline.git.branch >> @@ -61,8 +62,8 @@ executors: cy-doc: docker: - image: cypress/browsers:node16.5.0-chrome94-ff93 - # by default, we use "small" to save on CI costs. bump on a per-job basis if needed. - resource_class: small + # by default, we use "medium" to balance performance + CI costs. bump or reduce on a per-job basis if needed. + resource_class: medium environment: PLATFORM: linux @@ -142,6 +143,9 @@ commands: build-and-persist: description: Save entire folder as artifact for other jobs to run without reinstalling steps: + - run: + name: Build all codegen + command: yarn gulp buildProd - run: name: Build packages command: yarn build @@ -424,7 +428,7 @@ commands: yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> else # external PR - TESTFILES=$(circleci tests glob "cypress/integration/**/*spec.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL) + TESTFILES=$(circleci tests glob "cypress/e2e/**/*.cy.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL) echo "Test files for this machine are $TESTFILES" if [[ -z "$TESTFILES" ]]; then @@ -440,8 +444,12 @@ commands: path: /tmp/artifacts - store-npm-logs - run-runner-integration-tests: + run-new-ui-tests: parameters: + package: + description: package to target + type: enum + enum: ['frontend-shared', 'launchpad', 'app'] browser: description: browser shortname to target type: string @@ -449,55 +457,37 @@ commands: description: enable percy type: boolean default: false + type: + description: ct or e2e + type: enum + enum: ['ct', 'e2e'] + debug: + description: debug option + type: string + default: '' steps: - restore_cached_workspace + - run: + # TODO: How can we have preinstalled browsers on CircleCI? + name: 'Install Chrome on Windows' + command: | + # install with `--ignore-checksums` to avoid checksum error + # https://www.gep13.co.uk/blog/chocolatey-error-hashes-do-not-match + [[ $PLATFORM == 'windows' && '<>' == 'chrome' ]] && choco install googlechrome --ignore-checksums || [[ $PLATFORM != 'windows' ]] - run: command: | cmd=$([[ <> == 'true' ]] && echo 'yarn percy exec --parallel -- --') || true + DEBUG=<> \ CYPRESS_KONFIG_ENV=production \ - CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ + CYPRESS_RECORD_KEY=$TEST_LAUNCHPAD_RECORD_KEY \ PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ PERCY_ENABLE=${PERCY_TOKEN:-0} \ PERCY_PARALLEL_TOTAL=-1 \ - $cmd yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<> --browser <> - - verify-mocha-results + $cmd yarn workspace @packages/<> cypress:run:<> --browser <> --record --parallel --group <>-<> - store_test_results: path: /tmp/cypress - store_artifacts: - path: /tmp/artifacts - - store-npm-logs - - run-runner-ct-integration-tests: - parameters: - browser: - description: browser shortname to target - type: string - percy: - description: enable percy - type: boolean - default: false - steps: - - restore_cached_workspace - - run: - command: | - cmd=$([[ <> == 'true' ]] && echo 'yarn percy exec -- --') || true - PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ - PERCY_ENABLE=${PERCY_TOKEN:-0} \ - PERCY_PARALLEL_TOTAL=-1 \ - $cmd yarn workspace @packages/runner-ct run cypress:run --browser <> - - run: - command: | - if [[ <> == 'true' ]]; then - PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ - PERCY_ENABLE=${PERCY_TOKEN:-0} \ - PERCY_PARALLEL_TOTAL=-1 \ - yarn percy upload packages/runner-ct/cypress/screenshots/screenshot.spec.tsx/percy - else - echo "skipping percy screenshots uploading" - fi - - verify-mocha-results - - store_test_results: - path: /tmp/cypress + path: ./packages/<>/cypress/videos - store-npm-logs run-system-tests: @@ -576,13 +566,17 @@ commands: steps: - run: yarn verify:mocha:results <> - clone-repo-and-checkout-release-branch: + clone-repo-and-checkout-branch: description: | Clones an external repo and then checks out the branch that matches the next version otherwise uses 'master' branch. parameters: repo: description: "Name of the github repo to clone like: cypress-example-kitchensink" type: string + pull_request_id: + description: Pull request number to check out before installing and testing + type: integer + default: 0 steps: - restore_cached_binary - run: @@ -596,6 +590,15 @@ commands: NEXT_VERSION=$(node ./cypress/scripts/get-next-version.js) cd /tmp/<> && (git checkout $NEXT_VERSION || true) + - when: + condition: <> + steps: + - run: + name: Check out PR <> + working_directory: /tmp/<> + command: | + git fetch origin pull/<>/head:pr-<> + git checkout pr-<> test-binary-against-rwa: description: | @@ -637,7 +640,7 @@ commands: type: string default: "CI=true yarn start" steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: <> - when: condition: <> @@ -754,18 +757,9 @@ commands: type: string default: "npm start --if-present" steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: <> - - when: - condition: <> - steps: - - run: - name: Check out PR <> - working_directory: /tmp/<> - command: | - git fetch origin pull/<>/head:pr-<> - git checkout pr-<> - git log -n 2 + pull_request_id: <> - run: # Install deps + Cypress binary with yarn if yarn.lock present command: | @@ -777,6 +771,23 @@ commands: CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm install --legacy-peer-deps ~/cypress/cypress.tgz fi working_directory: /tmp/<> + - run: + name: Scaffold new config file + working_directory: /tmp/<> + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + if [[ -f cypress.json ]]; then + rm -rf cypress.json + echo 'module.exports = {}' > cypress.config.js + fi + - run: + name: Rename support file + working_directory: /tmp/<> + command: | + if [[ -f cypress/support/index.js ]]; then + mv cypress/support/index.js cypress/support/e2e.js + fi - run: name: Print Cypress version working_directory: /tmp/<> @@ -839,6 +850,17 @@ commands: command: <> - store-npm-logs + wait-on-circle-jobs: + description: Polls certain Circle CI jobs until they finish + parameters: + job-names: + description: comma separated list of circle ci job names to wait for + type: string + steps: + - run: + name: "Waiting on Circle CI jobs: <>" + command: node ./scripts/wait-on-circle-jobs.js --job-names="<>" + build-binary: steps: - run: @@ -900,9 +922,16 @@ commands: - run: name: Build NPM package command: yarn build --scope cypress + - run: + name: Copy Re-exported NPM Packages + command: node ./scripts/post-build.js + working_directory: cli - run: command: ls -la types working_directory: cli/build + - run: + command: ls -la vue vue2 mount-utils react + working_directory: cli/build - unless: condition: equal: [ *windows-executor, << parameters.executor >> ] @@ -1008,9 +1037,21 @@ jobs: command: node cli/bin/cypress info --dev - store-npm-logs - # closes the Percy build when required jobs are passing + check-ts: + <<: *defaults + steps: + - restore_cached_workspace + - install-required-node + - run: + name: Check TS Types + command: NODE_OPTIONS=--max_old_space_size=4096 yarn gulp checkTs + + + # a special job that keeps polling Circle and when all + # individual jobs are finished, it closes the Percy build percy-finalize: <<: *defaults + resource_class: small parameters: <<: *defaultsParameters required_env_var: @@ -1029,11 +1070,26 @@ jobs: echo "This is an external PR, cannot access other services" circleci-agent step halt fi - - run: PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 yarn percy build:finalize + - wait-on-circle-jobs: + job-names: > + cli-visual-tests, + reporter-integration-tests, + npm-design-system, + run-app-component-tests-chrome, + run-app-integration-tests-chrome, + run-frontend-shared-component-tests-chrome, + run-launchpad-component-tests-chrome, + run-launchpad-integration-tests-chrome, + run-webpack-dev-server-fresh-integration-tests, + run-vite-dev-server-fresh-integration-tests + - run: + command: | + PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ + yarn percy build:finalize cli-visual-tests: <<: *defaults - parallelism: 8 + resource_class: small steps: - restore_cached_workspace - run: mkdir -p cli/visual-snapshots @@ -1088,6 +1144,8 @@ jobs: - run: yarn lerna run build-prod --stream # run unit tests from each individual package - run: yarn test + # run type checking for each individual package + - run: yarn lerna run types - verify-mocha-results: expectedResultCount: 10 - store_test_results: @@ -1101,7 +1159,7 @@ jobs: unit-tests-release: <<: *defaults - resource_class: medium + resource_class: small parallelism: 1 steps: - restore_cached_workspace @@ -1110,7 +1168,6 @@ jobs: lint-types: <<: *defaults parallelism: 1 - resource_class: medium steps: - restore_cached_workspace - run: @@ -1122,9 +1179,10 @@ jobs: - run: name: "Lint types ๐Ÿงน" command: yarn workspace cypress dtslint - - run: - name: "TypeScript check ๐Ÿงฉ" - command: yarn type-check --ignore-progress + # todo(lachlan): do we need this? yarn check-ts does something very similar + # - run: + # name: "TypeScript check ๐Ÿงฉ" + # command: yarn type-check --ignore-progress - store-npm-logs server-unit-tests: @@ -1141,7 +1199,6 @@ jobs: server-integration-tests: <<: *defaults - resource_class: medium parallelism: 1 steps: - restore_cached_workspace @@ -1188,7 +1245,6 @@ jobs: system-tests-chrome: <<: *defaults - resource_class: medium parallelism: 8 steps: - run-system-tests: @@ -1196,7 +1252,6 @@ jobs: system-tests-electron: <<: *defaults - resource_class: medium parallelism: 8 steps: - run-system-tests: @@ -1204,7 +1259,6 @@ jobs: system-tests-firefox: <<: *defaults - resource_class: medium parallelism: 8 steps: - run-system-tests: @@ -1212,7 +1266,6 @@ jobs: system-tests-non-root: <<: *defaults - resource_class: medium steps: - restore_cached_workspace - run: @@ -1224,42 +1277,92 @@ jobs: path: /tmp/artifacts - store-npm-logs - runner-integration-tests-chrome: + run-frontend-shared-component-tests-chrome: <<: *defaults - resource_class: medium - parallelism: 2 + parameters: + <<: *defaultsParameters + percy: + type: boolean + default: false + parallelism: 3 steps: - - run-runner-integration-tests: + - run-new-ui-tests: browser: chrome - percy: true + percy: << parameters.percy >> + package: frontend-shared + type: ct - runner-integration-tests-firefox: + run-launchpad-component-tests-chrome: <<: *defaults - resource_class: medium - parallelism: 2 + parameters: + <<: *defaultsParameters + percy: + type: boolean + default: false + parallelism: 7 steps: - - run-runner-integration-tests: - browser: firefox - - runner-integration-tests-electron: - <<: *defaults - resource_class: medium - parallelism: 2 - steps: - - run-runner-integration-tests: - browser: electron - - runner-ct-integration-tests-chrome: - <<: *defaults - parallelism: 1 - steps: - - run-runner-ct-integration-tests: + - run-new-ui-tests: browser: chrome - percy: true + percy: << parameters.percy >> + package: launchpad + type: ct + # debug: cypress:*,engine:socket + + run-launchpad-integration-tests-chrome: + <<: *defaults + parameters: + <<: *defaultsParameters + resource_class: + type: string + default: medium + percy: + type: boolean + default: false + resource_class: << parameters.resource_class >> + parallelism: 3 + steps: + - run-new-ui-tests: + browser: chrome + percy: << parameters.percy >> + package: launchpad + type: e2e + + run-app-component-tests-chrome: + <<: *defaults + parameters: + <<: *defaultsParameters + percy: + type: boolean + default: false + parallelism: 7 + steps: + - run-new-ui-tests: + browser: chrome + percy: << parameters.percy >> + package: app + type: ct + + run-app-integration-tests-chrome: + <<: *defaults + parameters: + <<: *defaultsParameters + resource_class: + type: string + default: medium + percy: + type: boolean + default: false + resource_class: << parameters.resource_class >> + parallelism: 8 + steps: + - run-new-ui-tests: + browser: chrome + percy: << parameters.percy >> + package: app + type: e2e driver-integration-tests-chrome: <<: *defaults - resource_class: medium parallelism: 5 steps: - run-driver-integration-tests: @@ -1268,7 +1371,6 @@ jobs: driver-integration-tests-chrome-beta: <<: *defaults - resource_class: medium parallelism: 5 steps: - run-driver-integration-tests: @@ -1277,7 +1379,6 @@ jobs: driver-integration-tests-firefox: <<: *defaults - resource_class: medium parallelism: 5 steps: - run-driver-integration-tests: @@ -1285,60 +1386,14 @@ jobs: driver-integration-tests-electron: <<: *defaults - resource_class: medium parallelism: 5 steps: - run-driver-integration-tests: browser: electron - desktop-gui-integration-tests-7x: - <<: *defaults - parallelism: 7 - steps: - - restore_cached_workspace - - run: - command: yarn build-prod - working_directory: packages/desktop-gui - - run: - command: | - CYPRESS_KONFIG_ENV=production \ - CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ - PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ - PERCY_ENABLE=${PERCY_TOKEN:-0} \ - PERCY_PARALLEL_TOTAL=-1 \ - yarn percy exec --parallel -- -- \ - yarn cypress:run --record --parallel --group 2x-desktop-gui - working_directory: packages/desktop-gui - - verify-mocha-results - - store_test_results: - path: /tmp/cypress - - store_artifacts: - path: /tmp/artifacts - - store-npm-logs - - desktop-gui-component-tests: - <<: *defaults - resource_class: medium - parallelism: 1 - steps: - - restore_cached_workspace - - run: - # will use PERCY_TOKEN environment variable if available - command: | - CYPRESS_KONFIG_ENV=production \ - PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ - PERCY_ENABLE=${PERCY_TOKEN:-0} \ - PERCY_PARALLEL_TOTAL=-1 \ - yarn percy exec --parallel -- -- \ - yarn cypress:run:ct - working_directory: packages/desktop-gui - - verify-mocha-results - # we don't really need any artifacts - we are only interested in visual screenshots - - store-npm-logs - reporter-integration-tests: <<: *defaults - resource_class: medium + parallelism: 3 steps: - restore_cached_workspace - run: @@ -1361,6 +1416,50 @@ jobs: path: /tmp/artifacts - store-npm-logs + run-webpack-dev-server-fresh-integration-tests: + <<: *defaults + # parallelism: 3 TODO: Add parallelism once we have more specs + steps: + - restore_cached_workspace + - restore_cached_system_tests_deps + - run: + command: | + CYPRESS_KONFIG_ENV=production \ + CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ + PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ + PERCY_ENABLE=${PERCY_TOKEN:-0} \ + PERCY_PARALLEL_TOTAL=-1 \ + yarn percy exec --parallel -- -- \ + yarn cypress:run --record --parallel --group webpack-dev-server-fresh + working_directory: npm/webpack-dev-server-fresh + - store_test_results: + path: /tmp/cypress + - store_artifacts: + path: /tmp/artifacts + - store-npm-logs + + run-vite-dev-server-fresh-integration-tests: + <<: *defaults + # parallelism: 3 TODO: Add parallelism once we have more specs + steps: + - restore_cached_workspace + - restore_cached_system_tests_deps + - run: + command: | + CYPRESS_KONFIG_ENV=production \ + CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ + PERCY_PARALLEL_NONCE=$CIRCLE_SHA1 \ + PERCY_ENABLE=${PERCY_TOKEN:-0} \ + PERCY_PARALLEL_TOTAL=-1 \ + yarn percy exec --parallel -- -- \ + yarn cypress:run --record --parallel --group vite-dev-server-fresh + working_directory: npm/vite-dev-server-fresh + - store_test_results: + path: /tmp/cypress + - store_artifacts: + path: /tmp/artifacts + - store-npm-logs + ui-components-integration-tests: <<: *defaults steps: @@ -1422,9 +1521,13 @@ jobs: <<: *defaults steps: - restore_cached_workspace + - restore_cached_system_tests_deps - run: name: Run tests command: yarn workspace @cypress/webpack-dev-server test + - run: + name: Run tests + command: yarn workspace @cypress/webpack-dev-server-fresh test npm-vite-dev-server: <<: *defaults @@ -1440,6 +1543,7 @@ jobs: npm-webpack-batteries-included-preprocessor: <<: *defaults + resource_class: small steps: - restore_cached_workspace - run: @@ -1448,8 +1552,6 @@ jobs: npm-vue: <<: *defaults - resource_class: medium - parallelism: 3 steps: - restore_cached_workspace - run: @@ -1475,7 +1577,6 @@ jobs: npm-design-system: <<: *defaults - resource_class: medium steps: - restore_cached_workspace - run: @@ -1516,7 +1617,6 @@ jobs: npm-react: <<: *defaults parallelism: 8 - resource_class: medium steps: - restore_cached_workspace - run: @@ -1543,6 +1643,7 @@ jobs: npm-create-cypress-tests: <<: *defaults + resource_class: small steps: - restore_cached_workspace - run: yarn workspace create-cypress-tests build @@ -1560,6 +1661,7 @@ jobs: npm-cypress-schematic: <<: *defaults + resource_class: small steps: - restore_cached_workspace - run: @@ -1604,7 +1706,7 @@ jobs: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "unify-1449-beta-slug-length" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "unify-1449-check-path-length-in-build" && "$CIRCLE_BRANCH" != "10.0-release" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi @@ -1614,9 +1716,16 @@ jobs: test-kitchensink: <<: *defaults steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-example-kitchensink - install-required-node + - run: + name: Remove cypress.json + description: Remove cypress.json in case it exists + working_directory: /tmp/cypress-example-kitchensink + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: rm -rf cypress.json - run: name: Install prod dependencies command: yarn --production @@ -1626,6 +1735,13 @@ jobs: command: yarn start working_directory: /tmp/cypress-example-kitchensink background: true + - run: + name: Rename support file + working_directory: /tmp/cypress-example-kitchensink + command: | + if [[ -f cypress/support/index.js ]]; then + mv cypress/support/index.js cypress/support/e2e.js + fi - run: name: Run Kitchensink example project command: | @@ -1634,9 +1750,8 @@ jobs: test-kitchensink-against-staging: <<: *defaults - resource_class: medium steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-example-kitchensink - install-required-node - run: @@ -1660,9 +1775,8 @@ jobs: test-against-staging: <<: *defaults - resource_class: medium steps: - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-test-tiny - run: name: Run test project @@ -1711,6 +1825,7 @@ jobs: test-npm-module-on-minimum-node-version: <<: *defaults + resource_class: small docker: - image: cypress/base:12.0.0-libgbm steps: @@ -1748,6 +1863,7 @@ jobs: type: string default: /root/test-cypress-and-jest <<: *defaults + resource_class: small steps: - restore_workspace_binaries - run: mkdir <> @@ -1772,46 +1888,6 @@ jobs: echo "console.log('hello world')" > hello.ts npx tsc hello.ts --noEmit - # testing scaffolding examples and running them - # against example.cypress.io - test-cypress-scaffold: - resource_class: medium - parameters: - executor: - description: Executor name to use - type: executor - default: cy-doc - wd: - description: Working directory, should be OUTSIDE cypress monorepo folder - type: string - default: /root/test-scaffold - <<: *defaults - steps: - - restore_workspace_binaries - - run: mkdir <> - - run: - name: Create new NPM package โš—๏ธ - working_directory: <> - command: npm init -y - - run: - name: Install dependencies ๐Ÿ“ฆ - working_directory: <> - environment: - CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip - # let's install Cypress, Jest and any other package that might conflict - # https://github.com/cypress-io/cypress/issues/6690 - command: | - npm install /root/cypress/cypress.tgz \ - typescript jest @types/jest enzyme @types/enzyme - - run: - name: Scaffold and test examples ๐Ÿ— - working_directory: <> - environment: - CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" - command: | - echo '{}' > cypress.json - npx cypress run - test-full-typescript-project: parameters: executor: @@ -1823,6 +1899,7 @@ jobs: type: string default: /root/test-full-typescript <<: *defaults + resource_class: small steps: - restore_workspace_binaries - run: mkdir <> @@ -1841,6 +1918,40 @@ jobs: name: Scaffold full TypeScript project ๐Ÿ— working_directory: <> command: npx @bahmutov/cly@1 init --typescript + # TODO: fork/update @bahmutov/cly@1 to scaffold `cypress/e2e/spec.cy.ts` + # instead of `cypress/integration/spec.ts` when Cypress v10 is released. + - run: + name: Update example spec + working_directory: <> + command: | + mkdir cypress/e2e + mv cypress/integration/spec.ts cypress/e2e/spec.cy.ts + - run: + name: Scaffold new config file + working_directory: <> + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + rm -rf cypress.json + echo "export default { + e2e: { + setupNodeEvents (on, config) { + on('task', { + log (x) { + console.log(x) + + return null + }, + }) + + return config + }, + }, + }" > cypress.config.ts + - run: + name: Rename support file + working_directory: <> + command: mv cypress/support/index.ts cypress/support/e2e.js - run: name: Run project tests ๐Ÿ—ณ working_directory: <> @@ -1851,7 +1962,7 @@ jobs: <<: *defaults steps: - restore_workspace_binaries - - clone-repo-and-checkout-release-branch: + - clone-repo-and-checkout-branch: repo: cypress-test-tiny - run: name: Install Cypress @@ -1912,7 +2023,6 @@ jobs: test-binary-against-kitchensink: <<: *defaults - resource_class: medium steps: - test-binary-against-repo: repo: cypress-example-kitchensink @@ -1920,7 +2030,6 @@ jobs: test-binary-against-kitchensink-firefox: <<: *defaults - resource_class: medium steps: - test-binary-against-repo: repo: cypress-example-kitchensink @@ -1928,7 +2037,6 @@ jobs: test-binary-against-kitchensink-chrome: <<: *defaults - resource_class: medium steps: - test-binary-against-repo: repo: cypress-example-kitchensink @@ -1936,12 +2044,36 @@ jobs: test-binary-against-todomvc-firefox: <<: *defaults - resource_class: medium steps: - test-binary-against-repo: repo: cypress-example-todomvc browser: firefox + test-binary-against-conduit-chrome: + <<: *defaults + steps: + - test-binary-against-repo: + repo: cypress-example-conduit-app + browser: chrome + command: "npm run cypress:run" + wait-on: http://localhost:3000 + + test-binary-against-api-testing-firefox: + <<: *defaults + steps: + - test-binary-against-repo: + repo: cypress-example-api-testing + browser: firefox + command: "npm run cy:run" + + test-binary-against-piechopper-firefox: + <<: *defaults + steps: + - test-binary-against-repo: + repo: cypress-example-piechopper + browser: firefox + command: "npm run cypress:run" + test-binary-against-cypress-realworld-app: <<: *defaults resource_class: medium+ @@ -1953,7 +2085,6 @@ jobs: test-binary-as-specific-user: <<: *defaults - resource_class: medium steps: - restore_workspace_binaries # the user should be "node" @@ -1989,6 +2120,26 @@ jobs: name: Add Cypress demo working_directory: test-binary command: npx @bahmutov/cly init + # TODO: fork/update @bahmutov/cly@1 to scaffold `cypress/e2e/spec.cy.ts` + # instead of `cypress/integration/spec.js` when Cypress v10 is released. + - run: + name: Update example spec + working_directory: test-binary + command: | + mkdir cypress/e2e + mv cypress/integration/spec.js cypress/e2e/spec.cy.js + - run: + name: Scaffold new config file + working_directory: test-binary + environment: + CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" + command: | + rm -rf cypress.json + echo 'module.exports = {}' > cypress.config.js + - run: + name: Rename support file + working_directory: test-binary + command: mv cypress/support/index.js cypress/support/e2e.js - run: name: Verify Cypress binary working_directory: test-binary @@ -2005,6 +2156,9 @@ linux-workflow: &linux-workflow - build: requires: - node_modules_install + - check-ts: + requires: + - build - lint: name: linux-lint requires: @@ -2013,13 +2167,7 @@ linux-workflow: &linux-workflow context: test-runner:poll-circle-workflow required_env_var: PERCY_TOKEN # skips job if not defined (external PR) requires: - - desktop-gui-integration-tests-7x - - desktop-gui-component-tests - - cli-visual-tests - - runner-integration-tests-chrome - - runner-ct-integration-tests-chrome - - reporter-integration-tests - - npm-design-system + - build - lint-types: requires: - build @@ -2081,28 +2229,37 @@ linux-workflow: &linux-workflow context: test-runner:cypress-record-key requires: - build - - runner-integration-tests-chrome: + - run-frontend-shared-component-tests-chrome: + context: [test-runner:launchpad-tests, test-runner:percy] + percy: true + requires: + - build + - run-launchpad-integration-tests-chrome: + context: [test-runner:launchpad-tests, test-runner:percy] + percy: true + requires: + - build + - run-launchpad-component-tests-chrome: + context: [test-runner:launchpad-tests, test-runner:percy] + percy: true + requires: + - build + - run-app-integration-tests-chrome: + context: [test-runner:launchpad-tests, test-runner:percy] + percy: true + requires: + - build + - run-webpack-dev-server-fresh-integration-tests: context: [test-runner:cypress-record-key, test-runner:percy] requires: - - build - - runner-integration-tests-firefox: + - system-tests-node-modules-install + - run-vite-dev-server-fresh-integration-tests: context: [test-runner:cypress-record-key, test-runner:percy] requires: - - build - - runner-integration-tests-electron: - context: [test-runner:cypress-record-key, test-runner:percy] - requires: - - build - - runner-ct-integration-tests-chrome: - context: test-runner:percy - requires: - - build - - desktop-gui-integration-tests-7x: - context: [test-runner:cypress-record-key, test-runner:percy] - requires: - - build - - desktop-gui-component-tests: - context: test-runner:percy + - system-tests-node-modules-install + - run-app-component-tests-chrome: + context: [test-runner:launchpad-tests, test-runner:percy] + percy: true requires: - build - reporter-integration-tests: @@ -2115,7 +2272,7 @@ linux-workflow: &linux-workflow - build - npm-webpack-dev-server: requires: - - build + - system-tests-node-modules-install - npm-vite-dev-server: requires: - build @@ -2157,6 +2314,7 @@ linux-workflow: &linux-workflow context: test-runner:npm-release requires: - build + - check-ts - npm-angular - npm-eslint-plugin-dev - npm-create-cypress-tests @@ -2171,8 +2329,6 @@ linux-workflow: &linux-workflow - lint-types - linux-lint - percy-finalize - - runner-integration-tests-firefox - - runner-integration-tests-electron - driver-integration-tests-firefox - driver-integration-tests-chrome - driver-integration-tests-chrome-beta @@ -2188,6 +2344,14 @@ linux-workflow: &linux-workflow - ui-components-integration-tests - unit-tests - unit-tests-release + - cli-visual-tests + - reporter-integration-tests + - npm-design-system + - run-app-component-tests-chrome + - run-app-integration-tests-chrome + - run-frontend-shared-component-tests-chrome + - run-launchpad-component-tests-chrome + - run-launchpad-integration-tests-chrome # various testing scenarios, like building full binary # and testing it on a real project @@ -2216,9 +2380,6 @@ linux-workflow: &linux-workflow - test-types-cypress-and-jest: requires: - create-build-artifacts - - test-cypress-scaffold: - requires: - - create-build-artifacts - test-full-typescript-project: requires: - create-build-artifacts @@ -2331,6 +2492,22 @@ windows-workflow: &windows-workflow requires: - windows-node-modules-install + - run-app-integration-tests-chrome: + name: windows-run-app-integration-tests-chrome + executor: windows + resource_class: windows.medium + context: test-runner:launchpad-tests + requires: + - windows-build + + - run-launchpad-integration-tests-chrome: + name: windows-run-launchpad-integration-tests-chrome + executor: windows + resource_class: windows.medium + context: test-runner:launchpad-tests + requires: + - windows-build + - lint: name: windows-lint executor: windows diff --git a/cli/.gitignore b/cli/.gitignore index e288122700..e8d97c9244 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -12,3 +12,10 @@ types/sinon-chai types/net-stubbing.ts # ignore CLI output build folder build + +# ignore packages synced at build-time via +# the sync-exported-npm-with-cli.js script +vue +vue2 +react +mount-utils diff --git a/cli/README.md b/cli/README.md index bf34b3c1c2..3edb089d3c 100644 --- a/cli/README.md +++ b/cli/README.md @@ -60,6 +60,47 @@ yarn add ~/{your-dirs}/cypress/cli/build/cypress-3.3.1.tgz --ignore-scripts Which installs the `tgz` file we have just built from folder `Users/jane-lane/{your-dirs}/cypress/cli/build`. +#### Sub-package API + +> How do deep imports from cypress/* get resolved? + +The cypress npm package comes pre-assembled with mounting libraries for major front-end frameworks. These mounting libraries are the first examples of Cypress providing re-exported sub-packages. These sub-packages follow the same naming convention they do when they're published on **npm**, but without a leading **`@`** sign. For example: + +##### An example of a sub-package: @cypress/vue, @cypress/react, @cypress/mount-utils + +**Let's discuss the Vue mounting library that Cypress ships.** + +If you'd installed the `@cypress/vue` package from NPM, you could write the following code. + +This would be necessary when trying to use a version of Vue, React, or other library that may be newer or older than the current version of cypress itself. + +```js +import { mount } from '@cypress/vue' +``` + +Now, with the sub-package API, you're able to import the latest APIs directly from Cypress without needing to install a separate dependency. + +```js +import { mount } from 'cypress/vue' +``` + +The only difference is the import name, and if you still need to use a specific version of one of our external sub-packages, you may install it and import it directly. + +##### Adding a new sub-package + +There are a few steps when adding a new sub-package. + +1. Make sure the sub-package's rollup build is _self-contained_ or that any dependencies are also declared in the CLI's **`package.json`**. +2. Now, in the **`postbuild`** script for the sub-package you'd like to embed, invoke `node ./scripts/sync-exported-npm-with-cli.js` (relative to the sub-package, see **`npm/vue`** for an example). +3. Add the sub-package's name to the following locations: + - **`cli/.gitignore`** + - **`cli/scripts/post-build.js`** + - **`.eslintignore`** (under cli/sub-package) +4. DO NOT manually update the **package.json** file. Running `yarn build` will automate this process. +5. Commit the changed files. + +[Here is an example Pull Request](https://github.com/cypress-io/cypress/pull/20930/files#diff-21b1fe66043572c76c549a4fc5f186e9a69c330b186fc91116b9b70a4d047902) + #### Module API The module API can be tested locally using something like: diff --git a/cli/__snapshots__/cli_spec.js b/cli/__snapshots__/cli_spec.js index 2bf70683b4..e9f539f87e 100644 --- a/cli/__snapshots__/cli_spec.js +++ b/cli/__snapshots__/cli_spec.js @@ -16,22 +16,27 @@ exports['shows help for open --foo 1'] = ` Opens Cypress in the interactive GUI. Options: - -b, --browser path to a custom browser to be added to the - list of available browsers in Cypress + -b, --browser runs Cypress in the browser with the given + name. if a filesystem path is supplied, + Cypress will attempt to use the browser at + that path. + --component runs component tests -c, --config sets configuration values. separate multiple values with a comma. overrides any value in - cypress.json. - -C, --config-file path to JSON file where configuration values - are set. defaults to "cypress.json". pass - "false" to disable. + cypress.config.{ts|js}. + -C, --config-file path to script file where configuration + values are set. defaults to + "cypress.config.{ts|js}". -d, --detached [bool] runs Cypress application in detached mode + --e2e runs end to end tests -e, --env sets environment variables. separate multiple values with a comma. overrides any - value in cypress.json or cypress.env.json + value in cypress.config.{ts|js} or + cypress.env.json --global force Cypress into global mode as if its globally installed -p, --port runs Cypress on a specific port. overrides - any value in cypress.json. + any value in cypress.config.{ts|js}. -P, --project path to the project --dev runs cypress in development and bypasses binary check @@ -64,16 +69,18 @@ exports['shows help for run --foo 1'] = ` Options: -b, --browser runs Cypress in the browser with the given name. if a filesystem path is supplied, Cypress will attempt to use the browser at that path. --ci-build-id the unique identifier for a run on your CI provider. typically a "BUILD_ID" env var. this value is automatically detected for most CI providers - -c, --config sets configuration values. separate multiple values with a comma. overrides any value in cypress.json. - -C, --config-file path to JSON file where configuration values are set. defaults to "cypress.json". pass "false" to disable. - -e, --env sets environment variables. separate multiple values with a comma. overrides any value in cypress.json or cypress.env.json + --component runs component tests + -c, --config sets configuration values. separate multiple values with a comma. overrides any value in cypress.config.{ts|js}. + -C, --config-file path to script file where configuration values are set. defaults to "cypress.config.{ts|js}". + --e2e runs end to end tests + -e, --env sets environment variables. separate multiple values with a comma. overrides any value in cypress.config.{ts|js} or cypress.env.json --group a named group for recorded runs in the Cypress Dashboard -k, --key your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable. --headed displays the browser instead of running headlessly --headless hide the browser instead of running headed (default for cypress run) --no-exit keep the browser open after tests finish --parallel enables concurrent runs and automatic load balancing of specs across multiple machines or processes - -p, --port runs Cypress on a specific port. overrides any value in cypress.json. + -p, --port runs Cypress on a specific port. overrides any value in cypress.config.{ts|js}. -P, --project path to the project -q, --quiet run quietly, using only the configured reporter --record [bool] records the run. sends test results, screenshots and videos to your Cypress Dashboard. @@ -214,7 +221,9 @@ exports['cli help command shows help 1'] = ` open [options] Opens Cypress in the interactive GUI. run [options] Runs Cypress tests from the CLI without the GUI open-ct [options] Opens Cypress component testing interactive mode. - run-ct [options] Runs all Cypress Component Testing suites + Deprecated: use "open --component" + run-ct [options] Runs all Cypress component testing suites. Deprecated: + use "run --component" install [options] Installs the Cypress executable matching this package's version verify [options] Verifies that Cypress is installed correctly and @@ -252,7 +261,9 @@ exports['cli help command shows help for -h 1'] = ` open [options] Opens Cypress in the interactive GUI. run [options] Runs Cypress tests from the CLI without the GUI open-ct [options] Opens Cypress component testing interactive mode. - run-ct [options] Runs all Cypress Component Testing suites + Deprecated: use "open --component" + run-ct [options] Runs all Cypress component testing suites. Deprecated: + use "run --component" install [options] Installs the Cypress executable matching this package's version verify [options] Verifies that Cypress is installed correctly and @@ -290,7 +301,9 @@ exports['cli help command shows help for --help 1'] = ` open [options] Opens Cypress in the interactive GUI. run [options] Runs Cypress tests from the CLI without the GUI open-ct [options] Opens Cypress component testing interactive mode. - run-ct [options] Runs all Cypress Component Testing suites + Deprecated: use "open --component" + run-ct [options] Runs all Cypress component testing suites. Deprecated: + use "run --component" install [options] Installs the Cypress executable matching this package's version verify [options] Verifies that Cypress is installed correctly and @@ -329,7 +342,9 @@ exports['cli unknown command shows usage and exits 1'] = ` open [options] Opens Cypress in the interactive GUI. run [options] Runs Cypress tests from the CLI without the GUI open-ct [options] Opens Cypress component testing interactive mode. - run-ct [options] Runs all Cypress Component Testing suites + Deprecated: use "open --component" + run-ct [options] Runs all Cypress component testing suites. Deprecated: + use "run --component" install [options] Installs the Cypress executable matching this package's version verify [options] Verifies that Cypress is installed correctly and @@ -454,7 +469,9 @@ exports['cli CYPRESS_INTERNAL_ENV allows and warns when staging environment 1'] open [options] Opens Cypress in the interactive GUI. run [options] Runs Cypress tests from the CLI without the GUI open-ct [options] Opens Cypress component testing interactive mode. - run-ct [options] Runs all Cypress Component Testing suites + Deprecated: use "open --component" + run-ct [options] Runs all Cypress component testing suites. Deprecated: + use "run --component" install [options] Installs the Cypress executable matching this package's version verify [options] Verifies that Cypress is installed correctly and diff --git a/cli/__snapshots__/errors_spec.js b/cli/__snapshots__/errors_spec.js index e5ce248b8a..0b0fdd0135 100644 --- a/cli/__snapshots__/errors_spec.js +++ b/cli/__snapshots__/errors_spec.js @@ -26,31 +26,6 @@ Platform: test platform-x64 (Foo-OsVersion) Cypress Version: 1.2.3 ` -exports['errors individual has the following errors 1'] = [ - "CYPRESS_RUN_BINARY", - "binaryNotExecutable", - "childProcessKilled", - "failedDownload", - "failedUnzip", - "failedUnzipWindowsMaxPathLength", - "incompatibleHeadlessFlags", - "invalidCacheDirectory", - "invalidCypressEnv", - "invalidOS", - "invalidRunProjectPath", - "invalidSmokeTestDisplayError", - "invalidTestingType", - "missingApp", - "missingDependency", - "missingXvfb", - "nonZeroExitCodeXvfb", - "notInstalledCI", - "smokeTestFailure", - "unexpected", - "unknownError", - "versionMismatch" -] - exports['invalid display error'] = ` Cypress verification failed. @@ -97,3 +72,31 @@ Consider opening a new issue. Platform: test platform-x64 (Foo-OsVersion) Cypress Version: 1.2.3 ` + +exports['errors individual has the following errors 1'] = [ + "CYPRESS_RUN_BINARY", + "binaryNotExecutable", + "childProcessKilled", + "failedDownload", + "failedUnzip", + "failedUnzipWindowsMaxPathLength", + "incompatibleHeadlessFlags", + "incompatibleTestTypeFlags", + "incompatibleTestingTypeAndFlag", + "invalidCacheDirectory", + "invalidConfigFile", + "invalidCypressEnv", + "invalidOS", + "invalidRunProjectPath", + "invalidSmokeTestDisplayError", + "invalidTestingType", + "missingApp", + "missingDependency", + "missingXvfb", + "nonZeroExitCodeXvfb", + "notInstalledCI", + "smokeTestFailure", + "unexpected", + "unknownError", + "versionMismatch" +] diff --git a/cli/__snapshots__/run_spec.js b/cli/__snapshots__/run_spec.js index 5889b5b1b5..1d9b1bb4bf 100644 --- a/cli/__snapshots__/run_spec.js +++ b/cli/__snapshots__/run_spec.js @@ -21,13 +21,6 @@ exports['exec run .processRunOptions passes --record option 1'] = [ "my record id" ] -exports['exec run .processRunOptions passes --config-file false option 1'] = [ - "--run-project", - null, - "--config-file", - false -] - exports['exec run .processRunOptions defaults to e2e testingType 1'] = [ "--run-project", null diff --git a/cli/index.mjs b/cli/index.mjs new file mode 100644 index 0000000000..7b616f65a3 --- /dev/null +++ b/cli/index.mjs @@ -0,0 +1,15 @@ +import module from 'module' + +const require = module.createRequire(import.meta.url) + +const cypress = require('./lib/cypress') + +export default cypress + +export const defineConfig = cypress.defineConfig + +export const run = cypress.run + +export const open = cypress.open + +export const cli = cypress.cli diff --git a/cli/lib/cli.js b/cli/lib/cli.js index 1883a40643..b508f145ba 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -22,10 +22,6 @@ function unknownOption (flag, type = 'option') { } commander.Command.prototype.unknownOption = unknownOption -const coerceFalseOrString = (arg) => { - return arg !== 'false' ? arg : false -} - const coerceFalse = (arg) => { return arg !== 'false' } @@ -97,19 +93,20 @@ const parseVariableOpts = (fnArgs, args) => { } const descriptions = { - browserOpenMode: 'path to a custom browser to be added to the list of available browsers in Cypress', - browserRunMode: 'runs Cypress in the browser with the given name. if a filesystem path is supplied, Cypress will attempt to use the browser at that path.', + browser: 'runs Cypress in the browser with the given name. if a filesystem path is supplied, Cypress will attempt to use the browser at that path.', cacheClear: 'delete all cached binaries', cachePrune: 'deletes all cached binaries except for the version currently in use', cacheList: 'list cached binary versions', cachePath: 'print the path to the binary cache', cacheSize: 'Used with the list command to show the sizes of the cached folders', ciBuildId: 'the unique identifier for a run on your CI provider. typically a "BUILD_ID" env var. this value is automatically detected for most CI providers', - config: 'sets configuration values. separate multiple values with a comma. overrides any value in cypress.json.', - configFile: 'path to JSON file where configuration values are set. defaults to "cypress.json". pass "false" to disable.', + component: 'runs component tests', + config: 'sets configuration values. separate multiple values with a comma. overrides any value in cypress.config.{ts|js}.', + configFile: 'path to script file where configuration values are set. defaults to "cypress.config.{ts|js}".', detached: 'runs Cypress application in detached mode', dev: 'runs cypress in development and bypasses binary check', - env: 'sets environment variables. separate multiple values with a comma. overrides any value in cypress.json or cypress.env.json', + e2e: 'runs end to end tests', + env: 'sets environment variables. separate multiple values with a comma. overrides any value in cypress.config.{ts|js} or cypress.env.json', exit: 'keep the browser open after tests finish', forceInstall: 'force install the Cypress binary', global: 'force Cypress into global mode as if its globally installed', @@ -118,7 +115,7 @@ const descriptions = { headless: 'hide the browser instead of running headed (default for cypress run)', key: 'your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.', parallel: 'enables concurrent runs and automatic load balancing of specs across multiple machines or processes', - port: 'runs Cypress on a specific port. overrides any value in cypress.json.', + port: 'runs Cypress on a specific port. overrides any value in cypress.config.{ts|js}.', project: 'path to the project', quiet: 'run quietly, using only the configured reporter', record: 'records the run. sends test results, screenshots and videos to your Cypress Dashboard.', @@ -245,10 +242,12 @@ const addCypressRunCommand = (program) => { .command('run') .usage('[options]') .description('Runs Cypress tests from the CLI without the GUI') - .option('-b, --browser ', text('browserRunMode')) + .option('-b, --browser ', text('browser')) .option('--ci-build-id ', text('ciBuildId')) + .option('--component', text('component')) .option('-c, --config ', text('config')) .option('-C, --config-file ', text('configFile')) + .option('--e2e', text('e2e')) .option('-e, --env ', text('env')) .option('--group ', text('group')) .option('-k, --key ', text('key')) @@ -272,10 +271,12 @@ const addCypressOpenCommand = (program) => { .command('open') .usage('[options]') .description('Opens Cypress in the interactive GUI.') - .option('-b, --browser ', text('browserOpenMode')) + .option('-b, --browser ', text('browser')) + .option('--component', text('component')) .option('-c, --config ', text('config')) .option('-C, --config-file ', text('configFile')) .option('-d, --detached [bool]', text('detached'), coerceFalse) + .option('--e2e', text('e2e')) .option('-e, --env ', text('env')) .option('--global', text('global')) .option('-p, --port ', text('port')) @@ -283,6 +284,16 @@ const addCypressOpenCommand = (program) => { .option('--dev', text('dev'), coerceFalse) } +const maybeAddInspectFlags = (program) => { + if (process.argv.includes('--dev')) { + return program + .option('--inspect', 'Node option') + .option('--inspect-brk', 'Node option') + } + + return program +} + /** * Casts known command line options for "cypress run" to their intended type. * For example if the user passes "--port 5005" the ".port" property should be @@ -290,7 +301,7 @@ const addCypressOpenCommand = (program) => { * * Returns a clone of the original object. */ -const castCypressRunOptions = (opts) => { +const castCypressOptions = (opts) => { // only properties that have type "string | false" in our TS definition // require special handling, because CLI parsing takes care of purely // boolean arguments @@ -300,10 +311,6 @@ const castCypressRunOptions = (opts) => { castOpts.port = coerceAnyStringToInt(opts.port) } - if (_.has(opts, 'configFile')) { - castOpts.configFile = coerceFalseOrString(opts.configFile) - } - return castOpts } @@ -331,14 +338,55 @@ module.exports = { debug('creating program parser') const program = createProgram() - addCypressRunCommand(program) + maybeAddInspectFlags(addCypressRunCommand(program)) .action((...fnArgs) => { debug('parsed Cypress run %o', fnArgs) const options = parseVariableOpts(fnArgs, cliArgs) debug('parsed options %o', options) - const casted = castCypressRunOptions(options) + const casted = castCypressOptions(options) + + debug('casted options %o', casted) + resolve(casted) + }) + + debug('parsing args: %o', cliArgs) + program.parse(cliArgs) + }) + }, + + /** + * Parses `cypress open` command line option array into an object + * with options that you can feed into cy.openModeSystemTest test calls + * @example + * const options = parseOpenCommand(['cypress', 'open', '--browser', 'chrome']) + * // options is {browser: 'chrome'} + */ + parseOpenCommand (args) { + return new Promise((resolve, reject) => { + if (!Array.isArray(args)) { + return reject(new Error('Expected array of arguments')) + } + + // make a copy of the input arguments array + // and add placeholders where "node ..." would usually be + // also remove "cypress" keyword at the start if present + const cliArgs = args[0] === 'cypress' ? [...args.slice(1)] : [...args] + + cliArgs.unshift(null, null) + + debug('creating program parser') + const program = createProgram() + + maybeAddInspectFlags(addCypressOpenCommand(program)) + .action((...fnArgs) => { + debug('parsed Cypress open %o', fnArgs) + const options = parseVariableOpts(fnArgs, cliArgs) + + debug('parsed options %o', options) + + const casted = castCypressOptions(options) debug('casted options %o', casted) resolve(casted) @@ -400,7 +448,7 @@ module.exports = { showVersions(args) }) - addCypressOpenCommand(program) + maybeAddInspectFlags(addCypressOpenCommand(program)) .action((opts) => { debug('opening Cypress') require('./exec/open') @@ -409,7 +457,7 @@ module.exports = { .catch(util.logErrorExit1) }) - addCypressRunCommand(program) + maybeAddInspectFlags(addCypressRunCommand(program)) .action((...fnArgs) => { debug('running Cypress with args %o', fnArgs) require('./exec/run') @@ -421,8 +469,8 @@ module.exports = { program .command('open-ct') .usage('[options]') - .description('Opens Cypress component testing interactive mode.') - .option('-b, --browser ', text('browserOpenMode')) + .description('Opens Cypress component testing interactive mode. Deprecated: use "open --component"') + .option('-b, --browser ', text('browser')) .option('-c, --config ', text('config')) .option('-C, --config-file ', text('configFile')) .option('-d, --detached [bool]', text('detached'), coerceFalse) @@ -433,6 +481,17 @@ module.exports = { .option('--dev', text('dev'), coerceFalse) .action((opts) => { debug('opening Cypress') + + const msg = ` + ${logSymbols.warning} Warning: open-ct is deprecated and will be removed in a future release. + + Use \`cypress open --component\` instead. + ` + + logger.warn() + logger.warn(stripIndent(msg)) + logger.warn() + require('./exec/open') .start({ ...util.parseOpts(opts), testingType: 'component' }) .then(util.exit) @@ -442,8 +501,8 @@ module.exports = { program .command('run-ct') .usage('[options]') - .description('Runs all Cypress Component Testing suites') - .option('-b, --browser ', text('browserRunMode')) + .description('Runs all Cypress component testing suites. Deprecated: use "run --component"') + .option('-b, --browser ', text('browser')) .option('--ci-build-id ', text('ciBuildId')) .option('-c, --config ', text('config')) .option('-C, --config-file ', text('configFile')) @@ -465,6 +524,16 @@ module.exports = { .option('--dev', text('dev'), coerceFalse) .action((opts) => { debug('running Cypress run-ct') + + const msg = ` + ${logSymbols.warning} Warning: run-ct is deprecated and will be removed in a future release. + Use \`cypress run --component\` instead. + ` + + logger.warn() + logger.warn(stripIndent(msg)) + logger.warn() + require('./exec/run') .start({ ...util.parseOpts(opts), testingType: 'component' }) .then(util.exit) diff --git a/cli/lib/errors.js b/cli/lib/errors.js index 397123d5da..c10a86697d 100644 --- a/cli/lib/errors.js +++ b/cli/lib/errors.js @@ -227,6 +227,21 @@ const invalidTestingType = { solution: `Please provide a valid testingType. Valid test types are ${chalk.cyan('\'e2e\'')} and ${chalk.cyan('\'component\'')}.`, } +const incompatibleTestTypeFlags = { + description: '`--e2e` and `--component` cannot both be passed.', + solution: 'Either pass `--e2e` or `--component`, but not both.', +} + +const incompatibleTestingTypeAndFlag = { + description: 'Set a `testingType` and also passed `--e2e` or `--component` flags.', + solution: 'Either set `testingType` or pass a testing type flag, but not both.', +} + +const invalidConfigFile = { + description: '`--config-file` cannot be false.', + solution: 'Either pass a relative path to a valid Cypress config file or remove this option.', +} + /** * This error happens when CLI detects that the child Test Runner process * was killed with a signal, like SIGBUS @@ -420,5 +435,8 @@ module.exports = { incompatibleHeadlessFlags, invalidRunProjectPath, invalidTestingType, + incompatibleTestTypeFlags, + incompatibleTestingTypeAndFlag, + invalidConfigFile, }, } diff --git a/cli/lib/exec/open.js b/cli/lib/exec/open.js index 8590da727f..8765670b36 100644 --- a/cli/lib/exec/open.js +++ b/cli/lib/exec/open.js @@ -2,9 +2,19 @@ const debug = require('debug')('cypress:cli') const util = require('../util') const spawn = require('./spawn') const verify = require('../tasks/verify') -const { processTestingType } = require('./shared') +const { processTestingType, checkConfigFile } = require('./shared') +const { exitWithError } = require('../errors') -const processOpenOptions = (options) => { +/** + * Maps options collected by the CLI + * and forms list of CLI arguments to the server. + * + * Note: there is lightweight validation, with errors + * thrown synchronously. + * + * @returns {string[]} list of CLI arguments + */ +const processOpenOptions = (options = {}) => { if (!util.isInstalledGlobally() && !options.global && !options.project) { options.project = process.cwd() } @@ -16,6 +26,7 @@ const processOpenOptions = (options) => { } if (options.configFile !== undefined) { + checkConfigFile(options) args.push('--config-file', options.configFile) } @@ -35,7 +46,19 @@ const processOpenOptions = (options) => { args.push('--project', options.project) } - args.push(...processTestingType(options.testingType)) + if (options.global) { + args.push('--global', options.global) + } + + if (options.inspect) { + args.push('--inspect') + } + + if (options.inspectBrk) { + args.push('--inspectBrk') + } + + args.push(...processTestingType(options)) debug('opening from options %j', options) debug('command line arguments %j', args) @@ -46,14 +69,22 @@ const processOpenOptions = (options) => { module.exports = { processOpenOptions, start (options = {}) { - const args = processOpenOptions(options) - function open () { - return spawn.start(args, { - dev: options.dev, - detached: Boolean(options.detached), - stdio: 'inherit', - }) + try { + const args = processOpenOptions(options) + + return spawn.start(args, { + dev: options.dev, + detached: Boolean(options.detached), + stdio: 'inherit', + }) + } catch (err) { + if (err.details) { + return exitWithError(err.details)() + } + + throw err + } } if (options.dev) { diff --git a/cli/lib/exec/run.js b/cli/lib/exec/run.js index b5fac314e8..e070205901 100644 --- a/cli/lib/exec/run.js +++ b/cli/lib/exec/run.js @@ -5,7 +5,7 @@ const util = require('../util') const spawn = require('./spawn') const verify = require('../tasks/verify') const { exitWithError, errors } = require('../errors') -const { processTestingType, throwInvalidOptionError } = require('./shared') +const { processTestingType, throwInvalidOptionError, checkConfigFile } = require('./shared') /** * Typically a user passes a string path to the project. @@ -58,6 +58,7 @@ const processRunOptions = (options = {}) => { } if (options.configFile !== undefined) { + checkConfigFile(options) args.push('--config-file', options.configFile) } @@ -137,7 +138,15 @@ const processRunOptions = (options = {}) => { args.push('--tag', options.tag) } - args.push(...processTestingType(options.testingType)) + if (options.inspect) { + args.push('--inspect') + } + + if (options.inspectBrk) { + args.push('--inspectBrk') + } + + args.push(...processTestingType(options)) return args } @@ -156,10 +165,14 @@ module.exports = { }) function run () { - let args - try { - args = processRunOptions(options) + const args = processRunOptions(options) + + debug('run to spawn.start args %j', args) + + return spawn.start(args, { + dev: options.dev, + }) } catch (err) { if (err.details) { return exitWithError(err.details)() @@ -167,12 +180,6 @@ module.exports = { throw err } - - debug('run to spawn.start args %j', args) - - return spawn.start(args, { - dev: options.dev, - }) } if (options.dev) { diff --git a/cli/lib/exec/shared.js b/cli/lib/exec/shared.js index d861a1fe1e..3be0243dd9 100644 --- a/cli/lib/exec/shared.js +++ b/cli/lib/exec/shared.js @@ -23,23 +23,43 @@ const throwInvalidOptionError = (details) => { * @param {string} testingType The type of tests being executed * @returns {string[]} The array of new exec arguments */ -const processTestingType = (testingType) => { - if (testingType) { - if (testingType === 'e2e') { - return ['--testing-type', 'e2e'] - } +const processTestingType = (options) => { + if (options.e2e && options.component) { + return throwInvalidOptionError(errors.incompatibleTestTypeFlags) + } - if (testingType === 'component') { - return ['--testing-type', 'component'] - } + if (options.testingType && (options.component || options.e2e)) { + return throwInvalidOptionError(errors.incompatibleTestTypeFlags) + } + if (options.testingType === 'component' || options.component || options.ct) { + return ['--testing-type', 'component'] + } + + if (options.testingType === 'e2e' || options.e2e) { + return ['--testing-type', 'e2e'] + } + + if (options.testingType) { return throwInvalidOptionError(errors.invalidTestingType) } return [] } +/** + * Throws an error if configFile is string 'false' or boolean false + * @param {*} options + */ +const checkConfigFile = (options) => { + // CLI will parse as string, module API can pass in boolean + if (options.configFile === 'false' || options.configFile === false) { + throwInvalidOptionError(errors.invalidConfigFile) + } +} + module.exports = { throwInvalidOptionError, processTestingType, + checkConfigFile, } diff --git a/cli/lib/exec/spawn.js b/cli/lib/exec/spawn.js index 9d79f88dbd..6281fc393d 100644 --- a/cli/lib/exec/spawn.js +++ b/cli/lib/exec/spawn.js @@ -171,8 +171,13 @@ module.exports = { args.unshift(startScriptPath) } + if (process.env.CYPRESS_INTERNAL_DEV_DEBUG) { + args.unshift(process.env.CYPRESS_INTERNAL_DEV_DEBUG) + } + debug('spawn args %o %o', args, _.omit(stdioOptions, 'env')) debug('spawning Cypress with executable: %s', executable) + const child = cp.spawn(executable, args, stdioOptions) function resolveOn (event) { diff --git a/cli/lib/exec/xvfb.js b/cli/lib/exec/xvfb.js index 5b87e1810c..6918495af9 100644 --- a/cli/lib/exec/xvfb.js +++ b/cli/lib/exec/xvfb.js @@ -12,6 +12,7 @@ const debugXvfb = Debug('cypress:xvfb') debug.Debug = debugXvfb.Debug = Debug const xvfbOptions = { + displayNum: process.env.XVFB_DISPLAY_NUM, timeout: 30000, // milliseconds // need to explicitly define screen otherwise electron will crash // https://github.com/cypress-io/cypress/issues/6184 diff --git a/cli/lib/util.js b/cli/lib/util.js index d9250a200d..0473af32ba 100644 --- a/cli/lib/util.js +++ b/cli/lib/util.js @@ -198,12 +198,15 @@ const parseOpts = (opts) => { 'cacheClear', 'cachePrune', 'ciBuildId', + 'ct', + 'component', 'config', 'configFile', 'cypressVersion', 'destination', 'detached', 'dev', + 'e2e', 'exit', 'env', 'force', @@ -211,6 +214,8 @@ const parseOpts = (opts) => { 'group', 'headed', 'headless', + 'inspect', + 'inspectBrk', 'key', 'path', 'parallel', @@ -252,13 +257,17 @@ const getApplicationDataFolder = (...paths) => { const { env } = process // allow overriding the app_data folder - const folder = env.CYPRESS_KONFIG_ENV || env.CYPRESS_INTERNAL_ENV || 'development' + let folder = env.CYPRESS_KONFIG_ENV || env.CYPRESS_INTERNAL_ENV || 'development' const PRODUCT_NAME = pkg.productName || pkg.name const OS_DATA_PATH = ospath.data() const ELECTRON_APP_DATA_PATH = path.join(OS_DATA_PATH, PRODUCT_NAME) + if (process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF) { + folder = `${folder}-e2e-test` + } + const p = path.join(ELECTRON_APP_DATA_PATH, 'cy', folder, ...paths) return p diff --git a/cli/package.json b/cli/package.json index b1076a7cb1..d4f69fd5b8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -101,8 +101,13 @@ "bin", "lib", "index.js", + "index.mjs", "types/**/*.d.ts", - "types/net-stubbing.ts" + "types/net-stubbing.ts", + "mount-utils", + "vue", + "react", + "vue2" ], "bin": { "cypress": "bin/cypress" @@ -110,5 +115,30 @@ "engines": { "node": ">=12.0.0" }, - "types": "types" + "types": "types", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + }, + "./vue": { + "import": "./vue/dist/cypress-vue.esm-bundler.js", + "require": "./vue/dist/cypress-vue.cjs.js" + }, + "./vue2": { + "import": "./vue2/dist/cypress-vue2.esm-bundler.js", + "require": "./vue2/dist/cypress-vue2.cjs.js" + }, + "./package.json": { + "import": "./package.json", + "require": "./package.json" + }, + "./react": { + "import": "./react/dist/cypress-react.esm-bundler.js", + "require": "./react/dist/cypress-react.cjs.js" + }, + "./mount-utils": { + "require": "./mount-utils/dist/index.js" + } + } } diff --git a/cli/schema/README.md b/cli/schema/README.md deleted file mode 100644 index a7fe5c1849..0000000000 --- a/cli/schema/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# cypress.json file schema - -This [schema file](cypress.schema.json) provides definitions for -[various Cypress configuration](https://on.cypress.io/configuration) properties -inside `cypress.json` file. -When editing `cypress.json` the schema file is used by -[Schemastore](http://schemastore.org/json/) to provide IntelliSense and -validation. Works in modern text editors like VSCode, WebStorm and Atom with help with the -help of [autocomplete-json plugin](https://atom.io/packages/autocomplete-json). - -See [VSCode documentation](https://code.visualstudio.com/docs/languages/json) diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json deleted file mode 100644 index 752dba905a..0000000000 --- a/cli/schema/cypress.schema.json +++ /dev/null @@ -1,383 +0,0 @@ -{ - "title": "JSON schema for the https://cypress.io Test Runner's configuration file. Details at https://on.cypress.io/configuration", - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "definitions": { - "cypressConfig": { - "properties": { - "baseUrl": { - "type": "string", - "default": null, - "description": "Url used as prefix for cy.visit() or cy.request() commandโ€™s url. Example http://localhost:3030 or https://test.my-domain.com" - }, - "env": { - "type": "object", - "description": "Any values to be set as environment variables. See https://on.cypress.io/environment-variables", - "body": {} - }, - "ignoreTestFiles": { - "type": [ - "string", - "array" - ], - "items": { - "type": "string" - }, - "description": "A String or Array of glob patterns used to ignore test files that would otherwise be shown in your list of tests. Cypress uses minimatch with the options: {dot: true, matchBase: true}. We suggest using http://globtester.com to test what files would match." - }, - "numTestsKeptInMemory": { - "type": "number", - "default": 50, - "description": "The number of tests for which snapshots and command data are kept in memory. Reduce this number if you are experiencing high memory consumption in your browser during a test run." - }, - "port": { - "type": "number", - "default": null, - "description": "Port used to host Cypress. Normally this is a randomly generated port" - }, - "reporter": { - "type": "string", - "default": "spec", - "description": "The reporter used when running headlessly or in CI. See https://on.cypress.io/reporters" - }, - "reporterOptions": { - "type": "object", - "default": null, - "description": "The reporter options used. Supported options depend on the reporter. See https://on.cypress.io/reporters#Reporter-Options" - }, - "slowTestThreshold": { - "type": "number", - "default": 10000, - "description": "Slow test threshold in milliseconds. Only affects the visual output of some reporters. For example, the spec reporter will display the test time in yellow if over the threshold. See https://on.cypress.io/configuration#Timeouts" - }, - "testFiles": { - "type": [ - "string", - "array" - ], - "default": "**/*.*", - "description": "A String or Array of string glob patterns of the test files to load. See https://on.cypress.io/configuration#Global" - }, - "watchForFileChanges": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will watch and restart tests on test file changes" - }, - "defaultCommandTimeout": { - "type": "number", - "default": 4000, - "description": "Time, in milliseconds, to wait until most DOM based commands are considered timed out" - }, - "execTimeout": { - "type": "number", - "default": 60000, - "description": "Time, in milliseconds, to wait for a system command to finish executing during a cy.exec() command" - }, - "taskTimeout": { - "type": "number", - "default": 60000, - "description": "Time, in milliseconds, to wait for a task to finish executing during a cy.task() command" - }, - "pageLoadTimeout": { - "type": "number", - "default": 60000, - "description": "Time, in milliseconds, to wait for page transition events or cy.visit(), cy.go(), cy.reload() commands to fire their page load events. Network requests are limited by the underlying operating system, and may still time out if this value is increased." - }, - "requestTimeout": { - "type": "number", - "default": 5000, - "description": "Time, in milliseconds, to wait for an XHR request to go out in a cy.wait() command" - }, - "responseTimeout": { - "type": "number", - "default": 30000, - "description": "Time, in milliseconds, to wait until a response in a cy.request(), cy.wait(), cy.fixture(), cy.getCookie(), cy.getCookies(), cy.setCookie(), cy.clearCookie(), cy.clearCookies(), and cy.screenshot() commands" - }, - "fileServerFolder": { - "type": "string", - "default": "root project folder", - "description": "Path to folder where application files will attempt to be served from" - }, - "fixturesFolder": { - "type": [ - "string", - "boolean" - ], - "default": "cypress/fixtures", - "description": "Path to folder containing fixture files (Pass false to disable)" - }, - "integrationFolder": { - "type": "string", - "default": "cypress/integration", - "description": "Path to folder containing integration test files" - }, - "downloadsFolder": { - "type": "string", - "default": "cypress/downloads", - "description": "Path to folder where files downloaded during a test are saved" - }, - "componentFolder": { - "type": [ - "string", - "boolean" - ], - "default": false, - "description": "Path to folder containing component test files (Pass false to disable)" - }, - "pluginsFile": { - "type": [ - "string", - "boolean" - ], - "default": "cypress/plugins/index.js", - "description": "Path to plugins file. (Pass false to disable)" - }, - "screenshotOnRunFailure": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will take a screenshot when a test fails during cypress run" - }, - "screenshotsFolder": { - "type": "string", - "default": "cypress/screenshots", - "description": "Path to folder where screenshots will be saved from cy.screenshot() command or after a test fails during cypress run" - }, - "supportFile": { - "type": [ - "string", - "boolean" - ], - "default": "cypress/support/index.js", - "description": "Path to file to load before test files load. This file is compiled and bundled. (Pass false to disable)" - }, - "videosFolder": { - "type": "string", - "default": "cypress/videos", - "description": "Path to folder where videos will be saved during cypress run" - }, - "trashAssetsBeforeRuns": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will trash assets within the screenshotsFolder and videosFolder before tests run with cypress run" - }, - "videoCompression": { - "type": [ - "number", - "boolean" - ], - "default": 32, - "description": "The quality setting for the video compression, in Constant Rate Factor (CRF). The value can be false to disable compression or a value between 0 and 51, where a lower value results in better quality (at the expense of a higher file size)." - }, - "video": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will capture a video of the tests run with cypress run" - }, - "videoUploadOnPasses": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will process, compress, and upload videos to the Dashboard even when all tests in a spec file are passing. This only applies when recording your runs to the Dashboard. Turn this off if youโ€™d like to only upload the spec fileโ€™s video when there are failing tests." - }, - "chromeWebSecurity": { - "type": "boolean", - "default": true, - "description": "Whether Chrome Web Security for same-origin policy and insecure mixed content is enabled. Read more about this at https://on.cypress.io/web-security" - }, - "userAgent": { - "type": "string", - "default": null, - "description": "Enables you to override the default user agent the browser sends in all request headers. User agent values are typically used by servers to help identify the operating system, browser, and browser version. See User-Agent MDN Documentation for example user agent values here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent" - }, - "blockHosts": { - "type": [ - "string", - "array" - ], - "items": { - "type": "string" - }, - "default": null, - "description": "A String or Array of hosts that you wish to block traffic for. Please read the notes for examples on using this https://on.cypress.io/configuration#blockHosts" - }, - "modifyObstructiveCode": { - "type": "boolean", - "default": true, - "description": "Whether Cypress will search for and replace obstructive JS code found in .js or .html files that prevent Cypress from working. Please read the notes for more information on this setting. https://on.cypress.io/configuration#modifyObstructiveCode" - }, - "viewportHeight": { - "type": "number", - "default": 660, - "description": "Default height in pixels for the application under testsโ€™ viewport (Override with cy.viewport() command)" - }, - "viewportWidth": { - "type": "number", - "default": 1000, - "description": "Default width in pixels for the application under testsโ€™ viewport. (Override with cy.viewport() command)" - }, - "animationDistanceThreshold": { - "type": "number", - "default": 5, - "description": "The distance in pixels an element must exceed over time to be considered animating" - }, - "waitForAnimations": { - "type": "boolean", - "default": true, - "description": "Whether to wait for elements to finish animating before executing commands" - }, - "scrollBehavior": { - "enum": [ - false, - "center", - "top", - "bottom", - "nearest" - ], - "default": "top", - "description": "Viewport position to which an element should be scrolled prior to action commands. Setting `false` disables scrolling." - }, - "projectId": { - "type": "string", - "default": null, - "description": "A 6 character string use to identify this project in the Cypress Dashboard. See https://on.cypress.io/dashboard-service#Identification" - }, - "nodeVersion": { - "enum": [ - "system", - "bundled" - ], - "default": "system", - "description": "DEPRECATED: If set to 'bundled', Cypress will use the Node version bundled with Cypress. Otherwise, Cypress will use the Node version that was used to launch the Cypress. This Node version is used when executing your plugins file and building spec files." - }, - "experimentalInteractiveRunEvents": { - "type": "boolean", - "default": false, - "description": "Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode." - }, - "experimentalSourceRewriting": { - "type": "boolean", - "default": false, - "description": "Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm." - }, - "experimentalSessionSupport": { - "type": "boolean", - "default": false, - "description": "Enable experimental session support. See https://on.cypress.io/session" - }, - "experimentalFetchPolyfill": { - "type": "boolean", - "default": false, - "description": "Polyfills `window.fetch` to enable Network spying and stubbing" - }, - "experimentalStudio": { - "type": "boolean", - "default": false, - "description": "Generate and save commands directly to your test suite by interacting with your app as an end user would." - }, - "retries": { - "type": [ - "object", - "number", - "null" - ], - "default": { - "runMode": 0, - "openMode": 0 - }, - "description": "The number of times to retry a failing. Can be configured to apply only in runMode or openMode" - }, - "includeShadowDom": { - "type": "boolean", - "default": false, - "description": "Enables including elements within the shadow DOM when using querying commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.json, per-suite or per-test in the test configuration object, or programmatically with Cypress.config()" - }, - "clientCertificates": { - "description": "Defines client certificates to use when sending requests to the specified URLs", - "type": "array", - "items": { - "type": "object", - "properties": { - "url": { - "description": "Requests for URLs matching this minimatch pattern will use the supplied client certificate", - "type": "string" - }, - "ca": { - "description": "Path(s) to CA file(s) to validate certs against, relative to project root", - "type": "array", - "items": { - "type": "string" - } - }, - "certs": { - "type": "array", - "items": { - "anyOf": [ - { - "description": "PEM file specific properties", - "type": "object", - "properties": { - "cert": { - "description": "Path to the certificate, relative to project root", - "type": "string" - }, - "key": { - "description": "Path to the private key, relative to project root", - "type": "string" - }, - "passphrase": { - "description": "(Optional) File path to a UTF-8 text file containing the passphrase for the key, relative to project root", - "type": "string" - } - }, - "required": [ - "cert", - "key" - ] - }, - { - "description": "PFX file specific properties", - "type": "object", - "properties": { - "pfx": { - "description": "Path to the certificate container, relative to project root", - "type": "string" - }, - "passphrase": { - "description": "(Optional) File path to a UTF-8 text file containing the passphrase for the container, relative to project root", - "type": "string" - } - }, - "required": [ - "pfx" - ] - } - ] - } - } - }, - "required": [ - "url", - "certs" - ] - } - } - } - } - }, - "allOf": [ - { - "$ref": "#/definitions/cypressConfig" - }, - { - "properties": { - "component": { - "description": "Any component runner specific overrides", - "$ref": "#/definitions/cypressConfig" - }, - "e2e": { - "description": "Any e2e runner specific overrides", - "$ref": "#/definitions/cypressConfig" - } - } - } - ] -} diff --git a/cli/scripts/clean.js b/cli/scripts/clean.js index 34eac3ffd7..406d3b225a 100644 --- a/cli/scripts/clean.js +++ b/cli/scripts/clean.js @@ -1,8 +1,13 @@ -const shelljs = require('shelljs') +const fs = require('fs-extra') +const path = require('path') const { includeTypes } = require('./utils') -shelljs.rm('-rf', 'build') +fs.removeSync(path.join(__dirname, '..', 'build')) -includeTypes.map((m) => { - shelljs.rm('-rf', `types/${m}`) +includeTypes.forEach((folder) => { + try { + fs.removeSync(path.join(__dirname, '..', 'types', folder)) + } catch (e) { + // + } }) diff --git a/cli/scripts/post-build.js b/cli/scripts/post-build.js new file mode 100644 index 0000000000..98388b3f0d --- /dev/null +++ b/cli/scripts/post-build.js @@ -0,0 +1,22 @@ +const shell = require('shelljs') +const { resolve } = require('path') + +shell.set('-v') // verbose +shell.set('-e') // any error is fatal + +// For each npm package that is re-published via cypress/* +// make sure that it is also copied into the build directory +const npmModulesToCopy = [ + 'mount-utils', + 'react', + 'vue', + 'vue2', +] + +npmModulesToCopy.forEach((folder) => { + // cli/mount-utils => cli/build/mount-utils + const from = resolve(`${__dirname}/../${folder}`) + const to = resolve(`${__dirname}/../build/${folder}`) + + shell.cp('-R', from, to) +}) diff --git a/cli/scripts/post-install.js b/cli/scripts/post-install.js index 1cf84c3495..16c5b75a34 100644 --- a/cli/scripts/post-install.js +++ b/cli/scripts/post-install.js @@ -2,13 +2,14 @@ // @ts-check /* eslint-disable no-console */ - +const fs = require('fs-extra') const { includeTypes } = require('./utils') const shell = require('shelljs') -const fs = require('fs') const { join } = require('path') const resolvePkg = require('resolve-pkg') +require('./clean') + shell.set('-v') // verbose shell.set('-e') // any error is fatal @@ -19,10 +20,12 @@ shell.set('-e') // any error is fatal // yet we do not install "@types/.." packages with "npm install cypress" // because they can conflict with user's own libraries -includeTypes.forEach((folder) => { - const source = resolvePkg(`@types/${folder}`, { cwd: join(__dirname, '..', '..') }) +fs.ensureDirSync(join(__dirname, '..', 'types')) - shell.cp('-R', source, 'types') +includeTypes.forEach((folder) => { + const source = resolvePkg(`@types/${folder}`, { cwd: __dirname }) + + fs.copySync(source, join(__dirname, '..', 'types', folder)) }) // jQuery v3.3.x includes "dist" folder that just references back to itself @@ -72,7 +75,7 @@ shell.sed('-i', 'from \'sinon\';', 'from \'../sinon\';', sinonChaiFilename) // copy experimental network stubbing type definitions // so users can import: `import 'cypress/types/net-stubbing'` -shell.cp(resolvePkg('@packages/net-stubbing/lib/external-types.ts'), 'types/net-stubbing.ts') +fs.copySync(resolvePkg('@packages/net-stubbing/lib/external-types.ts'), 'types/net-stubbing.ts') // https://github.com/cypress-io/cypress/issues/18069 // To avoid type clashes, some files should be commented out entirely by patch-package @@ -90,7 +93,7 @@ filesToUncomment.forEach((file) => { const str = fs.readFileSync(filePath).toString() const result = str.split('\n').map((line) => { - return line.startsWith('// ') ? line.substring(3) : line + return line.startsWith('//z ') ? line.substring(4) : line }).join('\n') fs.writeFileSync(filePath, result) diff --git a/cli/scripts/start-build.js b/cli/scripts/start-build.js index b9263973e5..b22d27c146 100755 --- a/cli/scripts/start-build.js +++ b/cli/scripts/start-build.js @@ -22,5 +22,10 @@ includeTypes.forEach((folder) => { shell.cp('-R', source, 'build/types') }) +// TODO: Add a typescript or rollup build step +// The only reason start-build.js exists +// is because the cli package does not have an actual +// build process to compile index.js and lib shell.exec('babel lib -d build/lib') shell.exec('babel index.js -o build/index.js') +shell.cp('index.mjs', 'build/index.mjs') diff --git a/cli/test/lib/cli_spec.js b/cli/test/lib/cli_spec.js index 8b621c0db9..e5d8506fe0 100644 --- a/cli/test/lib/cli_spec.js +++ b/cli/test/lib/cli_spec.js @@ -630,12 +630,24 @@ describe('cli', () => { }) it('spawns server with correct args for component-testing', () => { + this.exec('open --component --dev') + expect(spawn.start.firstCall.args[0]).to.include('--testing-type') + expect(spawn.start.firstCall.args[0]).to.include('component') + }) + + it('spawns server with correct args for depricated component-testing command', () => { this.exec('open-ct --dev') expect(spawn.start.firstCall.args[0]).to.include('--testing-type') expect(spawn.start.firstCall.args[0]).to.include('component') }) it('runs server with correct args for component-testing', () => { + this.exec('run --component --dev') + expect(spawn.start.firstCall.args[0]).to.include('--testing-type') + expect(spawn.start.firstCall.args[0]).to.include('component') + }) + + it('runs server with correct args for depricated component-testing command', () => { this.exec('run-ct --dev') expect(spawn.start.firstCall.args[0]).to.include('--testing-type') expect(spawn.start.firstCall.args[0]).to.include('component') diff --git a/cli/test/lib/cypress_spec.js b/cli/test/lib/cypress_spec.js index d0515c15e0..44579d7ac9 100644 --- a/cli/test/lib/cypress_spec.js +++ b/cli/test/lib/cypress_spec.js @@ -53,18 +53,6 @@ describe('cypress', function () { expect(args).to.deep.eq({ config: JSON.stringify(config) }) }) }) - - it('passes configFile: false', () => { - const opts = { - configFile: false, - } - - return cypress.open(opts) - .then(getStartArgs) - .then((args) => { - expect(args).to.deep.eq(opts) - }) - }) }) context('.run fails to write results file', function () { @@ -152,18 +140,6 @@ describe('cypress', function () { return cypress.run().then(snapshot) }) - it('passes configFile: false', () => { - const opts = { - configFile: false, - } - - return cypress.run(opts) - .then(getStartArgs) - .then((args) => { - expect(args).to.deep.eq(opts) - }) - }) - it('rejects if project is an empty string', () => { return expect(cypress.run({ project: '' })).to.be.rejected }) @@ -223,30 +199,12 @@ describe('cypress', function () { }) }) - it('coerces --config-file false to boolean', async () => { - const args = 'cypress run --config-file false'.split(' ') + it('coerces --config-file cypress.config.js to string', async () => { + const args = 'cypress run --config-file cypress.config.js'.split(' ') const options = await cypress.cli.parseRunArguments(args) expect(options).to.deep.equal({ - configFile: false, - }) - }) - - it('coerces --config-file cypress.json to string', async () => { - const args = 'cypress run --config-file cypress.json'.split(' ') - const options = await cypress.cli.parseRunArguments(args) - - expect(options).to.deep.equal({ - configFile: 'cypress.json', - }) - }) - - it('parses config file false', async () => { - const args = 'cypress run --config-file false'.split(' ') - const options = await cypress.cli.parseRunArguments(args) - - expect(options).to.deep.equal({ - configFile: false, + configFile: 'cypress.config.js', }) }) diff --git a/cli/test/lib/exec/open_spec.js b/cli/test/lib/exec/open_spec.js index f9d3aa5878..d351771ce0 100644 --- a/cli/test/lib/exec/open_spec.js +++ b/cli/test/lib/exec/open_spec.js @@ -56,20 +56,11 @@ describe('exec open', function () { }) }) - it('spawns with --config-file false', function () { - return open.start({ configFile: false }) - .then(() => { - expect(spawn.start).to.be.calledWith( - ['--config-file', false], - ) - }) - }) - it('spawns with --config-file set', function () { - return open.start({ configFile: 'special-cypress.json' }) + return open.start({ configFile: 'special-cypress.config.js' }) .then(() => { expect(spawn.start).to.be.calledWith( - ['--config-file', 'special-cypress.json'], + ['--config-file', 'special-cypress.config.js'], ) }) }) @@ -142,7 +133,11 @@ describe('exec open', function () { }) it('throws if --testing-type is invalid', () => { - expect(() => open.start({ testingType: 'randomTestingType' })).to.throw() + expect(() => open.processOpenOptions({ testingType: 'randomTestingType' })).to.throw() + }) + + it('throws if --config-file is false', () => { + expect(() => open.processOpenOptions({ configFile: 'false' })).to.throw() }) }) }) diff --git a/cli/test/lib/exec/run_spec.js b/cli/test/lib/exec/run_spec.js index ef54d86cc7..a79d1a6e00 100644 --- a/cli/test/lib/exec/run_spec.js +++ b/cli/test/lib/exec/run_spec.js @@ -53,14 +53,6 @@ describe('exec run', function () { snapshot(args) }) - it('passes --config-file false option', () => { - const args = run.processRunOptions({ - configFile: false, - }) - - snapshot(args) - }) - it('does not allow setting paradoxical --headed and --headless flags', () => { os.platform.returns('linux') process.exit.returns() @@ -104,6 +96,18 @@ describe('exec run', function () { it('throws if testingType is invalid', () => { expect(() => run.processRunOptions({ testingType: 'randomTestingType' })).to.throw() }) + + it('throws if both e2e and component are set', () => { + expect(() => run.processRunOptions({ e2e: true, component: true })).to.throw() + }) + + it('throws if both testingType and component are set', () => { + expect(() => run.processRunOptions({ testingType: 'component', component: true })).to.throw() + }) + + it('throws if --config-file is false', () => { + expect(() => run.processRunOptions({ configFile: 'false' })).to.throw() + }) }) context('.start', function () { @@ -140,20 +144,11 @@ describe('exec run', function () { }) }) - it('spawns with --config-file false', function () { - return run.start({ configFile: false }) - .then(() => { - expect(spawn.start).to.be.calledWith( - ['--run-project', process.cwd(), '--config-file', false], - ) - }) - }) - it('spawns with --config-file set', function () { - return run.start({ configFile: 'special-cypress.json' }) + return run.start({ configFile: 'special-cypress.config.js' }) .then(() => { expect(spawn.start).to.be.calledWith( - ['--run-project', process.cwd(), '--config-file', 'special-cypress.json'], + ['--run-project', process.cwd(), '--config-file', 'special-cypress.config.js'], ) }) }) @@ -190,6 +185,20 @@ describe('exec run', function () { }) }) + it('spawns with --testing-type e2e when given --e2e', function () { + return run.start({ e2e: true }) + .then(() => { + expect(spawn.start).to.be.calledWith(['--run-project', process.cwd(), '--testing-type', 'e2e']) + }) + }) + + it('spawns with --testing-type component when given --component', function () { + return run.start({ component: true }) + .then(() => { + expect(spawn.start).to.be.calledWith(['--run-project', process.cwd(), '--testing-type', 'component']) + }) + }) + it('spawns with --tag value', function () { return run.start({ tag: 'nightly' }) .then(() => { diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index 50115be1e3..e41a11864b 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -37,7 +37,7 @@ declare namespace CypressCommandLine { interface CypressRunOptions extends CypressCommonOptions { /** * Specify browser to run tests in, either by name or by filesystem path - */ + */ browser: string /** * Specify a unique identifier for a run to enable grouping or parallelization @@ -91,10 +91,6 @@ declare namespace CypressCommandLine { * Specify mocha reporter options */ reporterOptions: any - /** - * Slow test threshold in milliseconds. Only affects the visual output of some reporters. For example, the spec reporter will display the test time in yellow if over the threshold. - */ - slowTestThreshold: number /** * Specify the specs to run */ @@ -146,11 +142,9 @@ declare namespace CypressCommandLine { /** * Path to the config file to be used. * - * If `false` is passed, no config file will be used. - * - * @default "cypress.json" + * @default "cypress.config.{ts|js}" */ - configFile: string | false + configFile: string /** * Specify environment variables. * TODO: isn't this duplicate of config.env?! @@ -395,7 +389,7 @@ declare module 'cypress' { * @param {Cypress.ConfigOptions} config * @returns {Cypress.ConfigOptions} the configuration passed in parameter */ - defineConfig(config: Cypress.ConfigOptions): Cypress.ConfigOptions + defineConfig(config: Cypress.ConfigOptions): Cypress.ConfigOptions } // export Cypress NPM module interface diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index bfb7c84822..fa9c20906c 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -174,7 +174,7 @@ declare namespace Cypress { /** * Spec type for the given test. "integration" is the default, but - * tests run using `open-ct` will be "component" + * tests run using `open --component` will be "component" * * @see https://on.cypress.io/experiments */ @@ -204,7 +204,7 @@ declare namespace Cypress { /** * The configuration for Cypress. */ - type Config = ResolvedConfigOptions & RuntimeConfigOptions + type Config = ResolvedConfigOptions & RuntimeConfigOptions & RuntimeServerConfigOptions /** * Several libraries are bundled with Cypress by default. @@ -398,7 +398,7 @@ declare namespace Cypress { // no real way to type without generics /** - * Returns all environment variables set with CYPRESS_ prefix or in "env" object in "cypress.json" + * Returns all environment variables set with CYPRESS_ prefix or in "env" object in "cypress.config.{ts|js}" * * @see https://on.cypress.io/env */ @@ -407,7 +407,7 @@ declare namespace Cypress { * Returns specific environment variable or undefined * @see https://on.cypress.io/env * @example - * // cypress.json + * // cypress.config.js * { "env": { "foo": "bar" } } * Cypress.env("foo") // => bar */ @@ -676,7 +676,7 @@ declare namespace Cypress { * @see https://on.cypress.io/get * @example ``` - // Get the aliased โ€˜todosโ€™ elements + // Get the aliased 'todos' elements cy.get('ul#todos').as('todos') //...hack hack hack... // later retrieve the todos @@ -724,9 +724,9 @@ declare namespace Cypress { * * @see https://on.cypress.io/check * @example - * // Select the radio with the value of โ€˜USโ€™ + * // Select the radio with the value of 'US' * cy.get('[type="radio"]').check('US') - * // Check the checkboxes with the values โ€˜gaโ€™ and โ€˜caโ€™ + * // Check the checkboxes with the values 'ga' and 'ca' * cy.get('[type="checkbox"]').check(['ga', 'ca']) */ check(value: string | string[], options?: Partial): Chainable @@ -750,7 +750,7 @@ declare namespace Cypress { /** * Clear a specific browser cookie. - * Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldnโ€™t need to use this command unless youโ€™re using it to clear a specific cookie inside a single test. + * Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldn't need to use this command unless you're using it to clear a specific cookie inside a single test. * * @see https://on.cypress.io/clearcookie */ @@ -758,7 +758,7 @@ declare namespace Cypress { /** * Clear all browser cookies. - * Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldnโ€™t need to use this command unless youโ€™re using it to clear a specific cookie inside a single test. + * Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldn't need to use this command unless you're using it to clear a specific cookie inside a single test. * * @see https://on.cypress.io/clearcookies */ @@ -767,7 +767,7 @@ declare namespace Cypress { /** * Clear data in local storage. * Cypress automatically runs this command before each test to prevent state from being - * shared across tests. You shouldnโ€™t need to use this command unless youโ€™re using it + * shared across tests. You shouldn't need to use this command unless you're using it * to clear localStorage inside a single test. Yields `localStorage` object. * * @see https://on.cypress.io/clearlocalstorage @@ -799,7 +799,7 @@ declare namespace Cypress { /** * Clear data in local storage. * Cypress automatically runs this command before each test to prevent state from being - * shared across tests. You shouldnโ€™t need to use this command unless youโ€™re using it + * shared across tests. You shouldn't need to use this command unless you're using it * to clear localStorage inside a single test. Yields `localStorage` object. * * @see https://on.cypress.io/clearlocalstorage @@ -814,7 +814,7 @@ declare namespace Cypress { /** * Clear data in local storage. * Cypress automatically runs this command before each test to prevent state from being - * shared across tests. You shouldnโ€™t need to use this command unless youโ€™re using it + * shared across tests. You shouldn't need to use this command unless you're using it * to clear localStorage inside a single test. Yields `localStorage` object. * * @see https://on.cypress.io/clearlocalstorage @@ -851,8 +851,8 @@ declare namespace Cypress { /** * Click a DOM element at specific coordinates * - * @param {number} x The distance in pixels from the elementโ€™s left to issue the click. - * @param {number} y The distance in pixels from the elementโ€™s top to issue the click. + * @param {number} x The distance in pixels from the element's left to issue the click. + * @param {number} y The distance in pixels from the element's top to issue the click. * @see https://on.cypress.io/click * @example ``` @@ -1007,8 +1007,8 @@ declare namespace Cypress { /** * Double-click a DOM element at specific coordinates * - * @param {number} x The distance in pixels from the elementโ€™s left to issue the click. - * @param {number} y The distance in pixels from the elementโ€™s top to issue the click. + * @param {number} x The distance in pixels from the element's left to issue the click. + * @param {number} y The distance in pixels from the element's top to issue the click. * @see https://on.cypress.io/dblclick * @example ``` @@ -1037,8 +1037,8 @@ declare namespace Cypress { /** * Right-click a DOM element at specific coordinates * - * @param {number} x The distance in pixels from the elementโ€™s left to issue the click. - * @param {number} y The distance in pixels from the elementโ€™s top to issue the click. + * @param {number} x The distance in pixels from the element's left to issue the click. + * @param {number} y The distance in pixels from the element's top to issue the click. * @see https://on.cypress.io/rightclick * @example ``` @@ -1141,7 +1141,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/find * @example - * // Find the liโ€™s within the nav + * // Find the li's within the nav * cy.get('.left-nav>.nav').find('>li') */ find(selector: string, options?: Partial): Chainable> @@ -1213,7 +1213,7 @@ declare namespace Cypress { * Get one or more DOM elements by alias. * @see https://on.cypress.io/get#Alias * @example - * // Get the aliased โ€˜todosโ€™ elements + * // Get the aliased 'todos' elements * cy.get('ul#todos').as('todos') * //...hack hack hack... * //later retrieve the todos @@ -1236,7 +1236,7 @@ declare namespace Cypress { getCookies(options?: Partial): Chainable /** - * Navigate back or forward to the previous or next URL in the browserโ€™s history. + * Navigate back or forward to the previous or next URL in the browser's history. * * @see https://on.cypress.io/go */ @@ -1281,7 +1281,7 @@ declare namespace Cypress { invoke(propertyPath: string, ...args: any[]): Chainable /** - * Get a propertyโ€™s value on the previously yielded subject. + * Get a property's value on the previously yielded subject. * * @see https://on.cypress.io/its * @example @@ -1855,7 +1855,7 @@ declare namespace Cypress { */ stub(): Agent /** - * Stubs all the objectโ€™s methods. + * Stubs all the object's methods. * * @see https://on.cypress.io/stub * @example @@ -2113,11 +2113,11 @@ declare namespace Cypress { * @example * // Unchecks checkbox element * cy.get('[type="checkbox"]').uncheck() - * // Uncheck element with the id โ€˜saveUserNameโ€™ + * // Uncheck element with the id 'saveUserName' * cy.get('#saveUserName').uncheck() * // Uncheck all checkboxes * cy.get(':checkbox').uncheck() - * // Uncheck the checkbox with the value of โ€˜gaโ€™ + * // Uncheck the checkbox with the value of 'ga' * cy.get('input[type="checkbox"]').uncheck(['ga']) */ uncheck(options?: Partial): Chainable @@ -2126,7 +2126,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/uncheck * @example - * // Uncheck the checkbox with the value of โ€˜gaโ€™ + * // Uncheck the checkbox with the value of 'ga' * cy.get('input[type="checkbox"]').uncheck('ga') */ uncheck(value: string, options?: Partial): Chainable @@ -2135,7 +2135,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/uncheck * @example - * // Uncheck the checkbox with the value of โ€˜gaโ€™, 'ma' + * // Uncheck the checkbox with the value of 'ga', 'ma' * cy.get('input[type="checkbox"]').uncheck(['ga', 'ma']) */ uncheck(values: string[], options?: Partial): Chainable @@ -2625,9 +2625,9 @@ declare namespace Cypress { certs: PEMCert[] | PFXCert[] } - interface ResolvedConfigOptions { + interface ResolvedConfigOptions { /** - * Url used as prefix for [cy.visit()](https://on.cypress.io/visit) or [cy.request()](https://on.cypress.io/request) commandโ€™s url + * Url used as prefix for [cy.visit()](https://on.cypress.io/visit) or [cy.request()](https://on.cypress.io/request) command's url * @default null */ baseUrl: string | null @@ -2640,7 +2640,7 @@ declare namespace Cypress { * A String or Array of glob patterns used to ignore test files that would otherwise be shown in your list of tests. Cypress uses minimatch with the options: {dot: true, matchBase: true}. We suggest using http://globtester.com to test what files would match. * @default "*.hot-update.js" */ - ignoreTestFiles: string | string[] + excludeSpecPattern: string | string[] /** * The number of tests for which snapshots and command data are kept in memory. Reduce this number if you are experiencing high memory consumption in your browser during a test run. * @default 50 @@ -2711,11 +2711,6 @@ declare namespace Cypress { * @default "cypress/fixtures" */ fixturesFolder: string | false - /** - * Path to folder containing integration test files - * @default "cypress/integration" - */ - integrationFolder: string /** * Path to folder where files downloaded during a test are saved * @default "cypress/downloads" @@ -2726,11 +2721,6 @@ declare namespace Cypress { * @default "bundled" */ nodeVersion: 'system' | 'bundled' - /** - * Path to plugins file. (Pass false to disable) - * @default "cypress/plugins/index.js" - */ - pluginsFile: string | false /** * The application under test cannot redirect more than this limit. * @default 20 @@ -2752,13 +2742,13 @@ declare namespace Cypress { */ screenshotOnRunFailure: boolean /** - * Path to folder where screenshots will be saved from [cy.screenshot()](https://on.cypress.io/screenshot) command or after a headless or CI runโ€™s test failure + * Path to folder where screenshots will be saved from [cy.screenshot()](https://on.cypress.io/screenshot) command or after a headless or CI run's test failure * @default "cypress/screenshots" */ screenshotsFolder: string | false /** * Path to file to load before test files load. This file is compiled and bundled. (Pass false to disable) - * @default "cypress/support/index.js" + * @default "cypress/support/{e2e|component}.js" */ supportFile: string | false /** @@ -2782,7 +2772,7 @@ declare namespace Cypress { */ video: boolean /** - * Whether Cypress will upload the video to the Dashboard even if all tests are passing. This applies only when recording your runs to the Dashboard. Turn this off if youโ€™d like the video uploaded only when there are failing tests. + * Whether Cypress will upload the video to the Dashboard even if all tests are passing. This applies only when recording your runs to the Dashboard. Turn this off if you'd like the video uploaded only when there are failing tests. * @default true */ videoUploadOnPasses: boolean @@ -2792,12 +2782,12 @@ declare namespace Cypress { */ chromeWebSecurity: boolean /** - * Default height in pixels for the application under testsโ€™ viewport (Override with [cy.viewport()](https://on.cypress.io/viewport) command) + * Default height in pixels for the application under tests' viewport (Override with [cy.viewport()](https://on.cypress.io/viewport) command) * @default 660 */ viewportHeight: number /** - * Default width in pixels for the application under testsโ€™ viewport. (Override with [cy.viewport()](https://on.cypress.io/viewport) command) + * Default width in pixels for the application under tests' viewport. (Override with [cy.viewport()](https://on.cypress.io/viewport) command) * @default 1000 */ viewportWidth: number @@ -2831,11 +2821,6 @@ declare namespace Cypress { * @default false */ experimentalSourceRewriting: boolean - /** - * Generate and save commands directly to your test suite by interacting with your app as an end user would. - * @default false - */ - experimentalStudio: boolean /** * Number of times to retry a failed test. * If a number is set, tests will retry in both runMode and openMode. @@ -2845,7 +2830,7 @@ declare namespace Cypress { retries: Nullable, openMode?: Nullable }> /** * Enables including elements within the shadow DOM when using querying - * commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.json, + * commands (e.g. cy.get(), cy.find()). Can be set globally in cypress.config.{ts|js}, * per-suite or per-test in the test configuration object, or programmatically * with Cypress.config() * @default false @@ -2856,10 +2841,6 @@ declare namespace Cypress { * The list of hosts to be blocked */ blockHosts: null | string | string[] - /** - * Path to folder containing component test files. - */ - componentFolder: false | string /** * A unique ID for the project used for recording */ @@ -2871,7 +2852,7 @@ declare namespace Cypress { /** * Glob pattern to determine what test files to load. */ - testFiles: string | string[] + specPattern: string | string[] /** * The user agent the browser sends in all request headers. */ @@ -2885,34 +2866,41 @@ declare namespace Cypress { * Override default config options for Component Testing runner. * @default {} */ - component: Omit + component: ComponentConfigOptions /** * Override default config options for E2E Testing runner. * @default {} */ - e2e: Omit + e2e: Omit /** * An array of objects defining the certificates */ clientCertificates: ClientCertificate[] + + /** + * Handle Cypress plugins + */ + setupNodeEvents: (on: PluginEvents, config: PluginConfigOptions) => Promise | PluginConfigOptions | void + + indexHtmlFile: string } /** * Options appended to config object on runtime. */ - interface RuntimeConfigOptions { + interface RuntimeConfigOptions extends Partial { + /** + * Absolute path to the config file (default: /cypress.config.{ts|js}) + */ + configFile: string /** * CPU architecture, from Node `os.arch()` * * @see https://nodejs.org/api/os.html#os_os_arch */ arch: string - /** - * The browser Cypress is running on. - */ - browser: Browser /** * Available browsers found on your system. */ @@ -2941,21 +2929,32 @@ declare namespace Cypress { */ version: string + // Internal or Unlisted at server/lib/config_options + namespace: string + projectRoot: string + devServerPublicPathRoute: string + cypressBinaryRoot: string + } + + /** + * Optional options added before the server starts + */ + interface RuntimeServerConfigOptions { + /** + * The browser Cypress is running on. + */ + browser: Browser // Internal or Unlisted at server/lib/config_options autoOpen: boolean browserUrl: string clientRoute: string - configFile: string cypressEnv: string - devServerPublicPathRoute: string isNewProject: boolean isTextTerminal: boolean morgan: boolean - namespace: string parentTestsFolder: string parentTestsFolderDisplay: string projectName: string - projectRoot: string proxyUrl: string remote: RemoteState report: boolean @@ -2970,7 +2969,7 @@ declare namespace Cypress { xhrUrl: string } - interface TestConfigOverrides extends Partial> { + interface TestConfigOverrides extends Partial> { browser?: IsBrowserMatcher | IsBrowserMatcher[] keystrokeDelay?: number } @@ -2979,13 +2978,54 @@ declare namespace Cypress { * All configuration items are optional. */ type CoreConfigOptions = Partial> - type ConfigOptions = CoreConfigOptions & { e2e?: CoreConfigOptions, component?: CoreConfigOptions } - interface PluginConfigOptions extends ResolvedConfigOptions { - /** - * Absolute path to the config file (default: /cypress.json) or false - */ - configFile: string | false + interface DefineDevServerConfig { + // This interface can be extended by the user, to inject the types for their + // preferred bundler: e.g. + // + // import type * as webpack from 'webpack' + // + // declare global { + // namespace Cypress { + // interface DefineDevServerConfig { + // webpackConfig?: webpack.Configuration + // } + // } + // } + [key: string]: any + } + + type PickConfigOpt = T extends keyof DefineDevServerConfig ? DefineDevServerConfig[T] : any + + type DevServerFn = (cypressDevServerConfig: DevServerConfig, devServerConfig: ComponentDevServerOpts) => ResolvedDevServerConfig | Promise + + type DevServerConfigObject = { + bundler: 'webpack' + framework: 'react' | 'vue' | 'vue-cli' | 'nuxt' | 'create-react-app' + webpackConfig?: PickConfigOpt<'webpackConfig'> + } | { + bundler: 'vite' + framework: 'react' | 'vue' + viteConfig?: Omit, undefined>, 'base' | 'root'> + } + + interface ComponentConfigOptions extends Omit { + devServer: DevServerFn | DevServerConfigObject + devServerConfig?: ComponentDevServerOpts + } + + /** + * Config options that can be assigned on cypress.config.{ts|js} file + */ + type UserConfigOptions = Omit, 'baseUrl' | 'excludeSpecPattern' | 'supportFile' | 'specPattern' | 'indexHtmlFile'> + + /** + * Takes ComponentDevServerOpts to track the signature of the devServerConfig for the provided `devServer`, + * so we have proper completion for `devServerConfig` + */ + type ConfigOptions = Partial> + + interface PluginConfigOptions extends ResolvedConfigOptions, RuntimeConfigOptions { /** * Absolute path to the root of the project */ @@ -3279,7 +3319,7 @@ declare namespace Cypress { /** * Cypress will automatically apply the right authorization headers - * if youโ€™re attempting to visit an application that requires + * if you're attempting to visit an application that requires * Basic Authentication. * * @example @@ -3350,7 +3390,7 @@ declare namespace Cypress { interface Chainer { // chai /** - * Asserts that the targetโ€™s `type` is equal to the given string type. + * Asserts that the target's `type` is equal to the given string type. * Types are case insensitive. See the `type-detect` project page for info on the type detection algorithm: * https://github.com/chaijs/type-detect. * @example @@ -3369,7 +3409,7 @@ declare namespace Cypress { */ (chainer: 'be.above', value: number | Date): Chainable /** - * Asserts that the targetโ€™s `type` is equal to the given string type. + * Asserts that the target's `type` is equal to the given string type. * Types are case insensitive. See the `type-detect` project page for info on the type detection algorithm: * https://github.com/chaijs/type-detect. * @example @@ -3406,7 +3446,7 @@ declare namespace Cypress { */ (chainer: 'be.arguments'): Chainable /** - * Asserts that the target is a number thatโ€™s within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. + * Asserts that the target is a number that's within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. * @example * cy.wrap(5.1).should('be.approximately', 5, 0.5) * @alias closeTo @@ -3415,7 +3455,7 @@ declare namespace Cypress { */ (chainer: 'be.approximately', value: number, delta: number): Chainable /** - * Asserts that the target is a number thatโ€™s within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. + * Asserts that the target is a number that's within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. * @example * cy.wrap(5.1).should('be.closeTo', 5, 0.5) * @see http://chaijs.com/api/bdd/#method_closeto @@ -3423,7 +3463,7 @@ declare namespace Cypress { */ (chainer: 'be.closeTo', value: number, delta: number): Chainable /** - * When the target is a string or array, .empty asserts that the targetโ€™s length property is strictly (===) equal to 0 + * When the target is a string or array, .empty asserts that the target's length property is strictly (===) equal to 0 * @example * cy.wrap([]).should('be.empty') * cy.wrap('').should('be.empty') @@ -3590,7 +3630,7 @@ declare namespace Cypress { (chainer: 'contain', value: any): Chainable /** * When one argument is provided, `.decrease` asserts that the given function `subject` returns a lesser number when it's invoked after invoking the target function compared to when it's invoked beforehand. - * `.decrease` also causes all `.by` assertions that follow in the chain to assert how much lesser of a number is returned. it's often best to assert that the return value decreased by the expected amount, rather than asserting it decreased by any amount. + * `.decrease` also causes all `.by` assertions that follow in the chain to assert how much lesser of a number is returned. It's often best to assert that the return value decreased by the expected amount, rather than asserting it decreased by any amount. * @example * let val = 1 * function subtractTwo() { val -= 2 } @@ -3701,7 +3741,7 @@ declare namespace Cypress { */ (chainer: 'have.deep.property', value: string, obj: object): Chainable /** - * Asserts that the targetโ€™s `length` property is equal to the given number `n`. + * Asserts that the target's `length` property is equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length', 3) * cy.wrap('foo').should('have.length', 3) @@ -3711,7 +3751,7 @@ declare namespace Cypress { */ (chainer: 'have.length' | 'have.lengthOf', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is greater than to the given number `n`. + * Asserts that the target's `length` property is greater than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.greaterThan', 2) * cy.wrap('foo').should('have.length.greaterThan', 2) @@ -3720,7 +3760,7 @@ declare namespace Cypress { */ (chainer: 'have.length.greaterThan' | 'have.lengthOf.greaterThan', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is greater than to the given number `n`. + * Asserts that the target's `length` property is greater than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.gt', 2) * cy.wrap('foo').should('have.length.gt', 2) @@ -3729,7 +3769,7 @@ declare namespace Cypress { */ (chainer: 'have.length.gt' | 'have.lengthOf.gt' | 'have.length.above' | 'have.lengthOf.above', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is greater than or equal to the given number `n`. + * Asserts that the target's `length` property is greater than or equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.gte', 2) * cy.wrap('foo').should('have.length.gte', 2) @@ -3738,7 +3778,7 @@ declare namespace Cypress { */ (chainer: 'have.length.gte' | 'have.lengthOf.gte' | 'have.length.at.least' | 'have.lengthOf.at.least', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is less than to the given number `n`. + * Asserts that the target's `length` property is less than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.lessThan', 4) * cy.wrap('foo').should('have.length.lessThan', 4) @@ -3747,7 +3787,7 @@ declare namespace Cypress { */ (chainer: 'have.length.lessThan' | 'have.lengthOf.lessThan', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is less than to the given number `n`. + * Asserts that the target's `length` property is less than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.lt', 4) * cy.wrap('foo').should('have.length.lt', 4) @@ -3756,7 +3796,7 @@ declare namespace Cypress { */ (chainer: 'have.length.lt' | 'have.lengthOf.lt' | 'have.length.below' | 'have.lengthOf.below', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is less than or equal to the given number `n`. + * Asserts that the target's `length` property is less than or equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.lte', 4) * cy.wrap('foo').should('have.length.lte', 4) @@ -3765,7 +3805,7 @@ declare namespace Cypress { */ (chainer: 'have.length.lte' | 'have.lengthOf.lte' | 'have.length.at.most' | 'have.lengthOf.at.most', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is within `start` and `finish`. + * Asserts that the target's `length` property is within `start` and `finish`. * @example * cy.wrap([1, 2, 3]).should('have.length.within', 1, 5) * @see http://chaijs.com/api/bdd/#method_lengthof @@ -3842,9 +3882,9 @@ declare namespace Cypress { * When one argument is provided, `.increase` asserts that the given function `subject` returns a greater number when it's * invoked after invoking the target function compared to when it's invoked beforehand. * `.increase` also causes all `.by` assertions that follow in the chain to assert how much greater of a number is returned. - * it's often best to assert that the return value increased by the expected amount, rather than asserting it increased by any amount. + * It's often best to assert that the return value increased by the expected amount, rather than asserting it increased by any amount. * - * When two arguments are provided, `.increase` asserts that the value of the given object `subject`โ€™s `prop` property is greater after + * When two arguments are provided, `.increase` asserts that the value of the given object `subject`'s `prop` property is greater after * invoking the target function compared to beforehand. * * @example @@ -3929,7 +3969,7 @@ declare namespace Cypress { */ (chainer: 'be.extensible'): Chainable /** - * Asserts that the target is sealed, which means that new properties canโ€™t be added to it, and its existing properties canโ€™t be reconfigured or deleted. + * Asserts that the target is sealed, which means that new properties can't be added to it, and its existing properties can't be reconfigured or deleted. * @example * let sealedObject = Object.seal({}) * let frozenObject = Object.freeze({}) @@ -3940,7 +3980,7 @@ declare namespace Cypress { */ (chainer: 'be.sealed'): Chainable /** - * Asserts that the target is frozen, which means that new properties canโ€™t be added to it, and its existing properties canโ€™t be reassigned to different values, reconfigured, or deleted. + * Asserts that the target is frozen, which means that new properties can't be added to it, and its existing properties can't be reassigned to different values, reconfigured, or deleted. * @example * let frozenObject = Object.freeze({}) * cy.wrap(frozenObject).should('be.frozen') @@ -3949,7 +3989,7 @@ declare namespace Cypress { */ (chainer: 'be.frozen'): Chainable /** - * Asserts that the target is a number, and isnโ€™t `NaN` or positive/negative `Infinity`. + * Asserts that the target is a number, and isn't `NaN` or positive/negative `Infinity`. * @example * cy.wrap(1).should('be.finite') * @see http://chaijs.com/api/bdd/#method_finite @@ -3959,7 +3999,7 @@ declare namespace Cypress { // chai.not /** - * Asserts that the targetโ€™s `type` is not equal to the given string type. + * Asserts that the target's `type` is not equal to the given string type. * Types are case insensitive. See the `type-detect` project page for info on the type detection algorithm: * https://github.com/chaijs/type-detect. * @example @@ -3978,7 +4018,7 @@ declare namespace Cypress { */ (chainer: 'not.be.above', value: number | Date): Chainable /** - * Asserts that the targetโ€™s `type` is not equal to the given string type. + * Asserts that the target's `type` is not equal to the given string type. * Types are case insensitive. See the `type-detect` project page for info on the type detection algorithm: * https://github.com/chaijs/type-detect. * @example @@ -4015,7 +4055,7 @@ declare namespace Cypress { */ (chainer: 'not.be.arguments'): Chainable /** - * Asserts that the target is a not number thatโ€™s within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. + * Asserts that the target is a not number that's within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. * @example * cy.wrap(5.1).should('not.be.approximately', 6, 0.5) * @alias closeTo @@ -4024,7 +4064,7 @@ declare namespace Cypress { */ (chainer: 'not.be.approximately', value: number, delta: number): Chainable /** - * Asserts that the target is not a number thatโ€™s within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. + * Asserts that the target is not a number that's within a given +/- `delta` range of the given number `expected`. However, it's often best to assert that the target is equal to its expected value. * @example * cy.wrap(5.1).should('not.be.closeTo', 6, 0.5) * @see http://chaijs.com/api/bdd/#method_closeto @@ -4032,7 +4072,7 @@ declare namespace Cypress { */ (chainer: 'not.be.closeTo', value: number, delta: number): Chainable /** - * When the target is a not string or array, .empty asserts that the targetโ€™s length property is strictly (===) equal to 0 + * When the target is a not string or array, .empty asserts that the target's length property is strictly (===) equal to 0 * @example * cy.wrap([1]).should('not.be.empty') * cy.wrap('foo').should('not.be.empty') @@ -4199,7 +4239,7 @@ declare namespace Cypress { (chainer: 'not.contain', value: any): Chainable /** * When one argument is provided, `.decrease` asserts that the given function `subject` does not returns a lesser number when it's invoked after invoking the target function compared to when it's invoked beforehand. - * `.decrease` also causes all `.by` assertions that follow in the chain to assert how much lesser of a number is returned. it's often best to assert that the return value decreased by the expected amount, rather than asserting it decreased by any amount. + * `.decrease` also causes all `.by` assertions that follow in the chain to assert how much lesser of a number is returned. It's often best to assert that the return value decreased by the expected amount, rather than asserting it decreased by any amount. * @example * let val = 1 * function subtractTwo() { val -= 2 } @@ -4285,7 +4325,7 @@ declare namespace Cypress { */ (chainer: 'not.have.deep.property', value: string, obj: object): Chainable /** - * Asserts that the targetโ€™s `length` property is not equal to the given number `n`. + * Asserts that the target's `length` property is not equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length', 2) * cy.wrap('foo').should('not.have.length', 2) @@ -4295,7 +4335,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length' | 'not.have.lengthOf', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is not greater than to the given number `n`. + * Asserts that the target's `length` property is not greater than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.greaterThan', 4) * cy.wrap('foo').should('not.have.length.greaterThan', 4) @@ -4304,7 +4344,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.greaterThan' | 'not.have.lengthOf.greaterThan', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is not greater than to the given number `n`. + * Asserts that the target's `length` property is not greater than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.gt', 4) * cy.wrap('foo').should('not.have.length.gt', 4) @@ -4313,7 +4353,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.gt' | 'not.have.lengthOf.gt' | 'not.have.length.above' | 'not.have.lengthOf.above', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is not greater than or equal to the given number `n`. + * Asserts that the target's `length` property is not greater than or equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.gte', 4) * cy.wrap('foo').should('not.have.length.gte', 4) @@ -4322,7 +4362,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.gte' | 'not.have.lengthOf.gte' | 'not.have.length.at.least' | 'not.have.lengthOf.at.least', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is less than to the given number `n`. + * Asserts that the target's `length` property is less than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('have.length.lessThan', 2) * cy.wrap('foo').should('have.length.lessThan', 2) @@ -4331,7 +4371,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.lessThan' | 'not.have.lengthOf.lessThan', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is not less than to the given number `n`. + * Asserts that the target's `length` property is not less than to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.lt', 2) * cy.wrap('foo').should('not.have.length.lt', 2) @@ -4340,7 +4380,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.lt' | 'not.have.lengthOf.lt' | 'not.have.length.below' | 'not.have.lengthOf.below', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is not less than or equal to the given number `n`. + * Asserts that the target's `length` property is not less than or equal to the given number `n`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.lte', 2) * cy.wrap('foo').should('not.have.length.lte', 2) @@ -4349,7 +4389,7 @@ declare namespace Cypress { */ (chainer: 'not.have.length.lte' | 'not.have.lengthOf.lte' | 'not.have.length.at.most' | 'not.have.lengthOf.at.most', value: number): Chainable /** - * Asserts that the targetโ€™s `length` property is within `start` and `finish`. + * Asserts that the target's `length` property is within `start` and `finish`. * @example * cy.wrap([1, 2, 3]).should('not.have.length.within', 6, 12) * @see http://chaijs.com/api/bdd/#method_lengthof @@ -4426,9 +4466,9 @@ declare namespace Cypress { * When one argument is provided, `.increase` asserts that the given function `subject` returns a greater number when it's * invoked after invoking the target function compared to when it's invoked beforehand. * `.increase` also causes all `.by` assertions that follow in the chain to assert how much greater of a number is returned. - * it's often best to assert that the return value increased by the expected amount, rather than asserting it increased by any amount. + * It's often best to assert that the return value increased by the expected amount, rather than asserting it increased by any amount. * - * When two arguments are provided, `.increase` asserts that the value of the given object `subject`โ€™s `prop` property is greater after + * When two arguments are provided, `.increase` asserts that the value of the given object `subject`'s `prop` property is greater after * invoking the target function compared to beforehand. * * @example @@ -4514,7 +4554,7 @@ declare namespace Cypress { */ (chainer: 'not.be.extensible'): Chainable /** - * Asserts that the target is sealed, which means that new properties canโ€™t be added to it, and its existing properties canโ€™t be reconfigured or deleted. + * Asserts that the target is sealed, which means that new properties can't be added to it, and its existing properties can't be reconfigured or deleted. * @example * cy.wrap({a: 1}).should('be.sealed') * cy.wrap({a: 1}).should('be.sealed') @@ -4523,7 +4563,7 @@ declare namespace Cypress { */ (chainer: 'not.be.sealed'): Chainable /** - * Asserts that the target is frozen, which means that new properties canโ€™t be added to it, and its existing properties canโ€™t be reassigned to different values, reconfigured, or deleted. + * Asserts that the target is frozen, which means that new properties can't be added to it, and its existing properties can't be reassigned to different values, reconfigured, or deleted. * @example * cy.wrap({a: 1}).should('not.be.frozen') * @see http://chaijs.com/api/bdd/#method_frozen @@ -4531,7 +4571,7 @@ declare namespace Cypress { */ (chainer: 'not.be.frozen'): Chainable /** - * Asserts that the target is a number, and isnโ€™t `NaN` or positive/negative `Infinity`. + * Asserts that the target is a number, and isn't `NaN` or positive/negative `Infinity`. * @example * cy.wrap(NaN).should('not.be.finite') * cy.wrap(Infinity).should('not.be.finite') @@ -4543,7 +4583,7 @@ declare namespace Cypress { // sinon-chai /** * Assert spy/stub was called the `new` operator. - * Beware that this is inferred based on the value of the this object and the spy functionโ€™s prototype, so it may give false positives if you actively return the right kind of object. + * Beware that this is inferred based on the value of the this object and the spy function's prototype, so it may give false positives if you actively return the right kind of object. * @see http://sinonjs.org/releases/v4.1.3/spies/#spycalledwithnew * @see https://on.cypress.io/assertions */ @@ -4616,7 +4656,7 @@ declare namespace Cypress { (chainer: 'be.calledWithMatch' | 'have.been.calledWithMatch', ...args: any[]): Chainable /** * Assert spy/stub was called the `new` operator. - * Beware that this is inferred based on the value of the this object and the spy functionโ€™s prototype, so it may give false positives if you actively return the right kind of object. + * Beware that this is inferred based on the value of the this object and the spy function's prototype, so it may give false positives if you actively return the right kind of object. * @see http://sinonjs.org/releases/v4.1.3/spies/#spycalledwithnew * @see https://on.cypress.io/assertions */ @@ -4703,7 +4743,7 @@ declare namespace Cypress { // sinon-chai.not /** * Assert spy/stub was not called the `new` operator. - * Beware that this is inferred based on the value of the this object and the spy functionโ€™s prototype, so it may give false positives if you actively return the right kind of object. + * Beware that this is inferred based on the value of the this object and the spy function's prototype, so it may give false positives if you actively return the right kind of object. * @see http://sinonjs.org/releases/v4.1.3/spies/#spycalledwithnew * @see https://on.cypress.io/assertions */ @@ -4776,7 +4816,7 @@ declare namespace Cypress { (chainer: 'not.be.calledWithMatch' | 'not.have.been.calledWithMatch', ...args: any[]): Chainable /** * Assert spy/stub was not called the `new` operator. - * Beware that this is inferred based on the value of the this object and the spy functionโ€™s prototype, so it may give false positives if you actively return the right kind of object. + * Beware that this is inferred based on the value of the this object and the spy function's prototype, so it may give false positives if you actively return the right kind of object. * @see http://sinonjs.org/releases/v4.1.3/spies/#spycalledwithnew * @see https://on.cypress.io/assertions */ @@ -5327,7 +5367,7 @@ declare namespace Cypress { /** * Create an assertion. Assertions are automatically retried until they pass or time out. - * Passing a function to `.should()` enables you to make multiple assertions on the yielded subject. This also gives you the opportunity to massage what youโ€™d like to assert on. + * Passing a function to `.should()` enables you to make multiple assertions on the yielded subject. This also gives you the opportunity to massage what you'd like to assert on. * Just be sure _not_ to include any code that has side effects in your callback function. The callback function will be retried over and over again until no assertions within it throw. * @example * cy @@ -5432,7 +5472,7 @@ declare namespace Cypress { interface ResolvedDevServerConfig { port: number - close: (done?: () => any) => void + close: (done?: (err?: Error) => any) => void } interface PluginEvents { @@ -5465,7 +5505,7 @@ declare namespace Cypress { ``` // likely want to do this in a support file // so it's applied to all spec files - // cypress/support/index.js + // cypress/support/{e2e|component}.js Cypress.on('uncaught:exception', (err, runnable) => { // returning false here prevents Cypress from diff --git a/cli/types/tests/cypress-npm-api-test.ts b/cli/types/tests/cypress-npm-api-test.ts index 776a54aeb5..dd2bbd9f29 100644 --- a/cli/types/tests/cypress-npm-api-test.ts +++ b/cli/types/tests/cypress-npm-api-test.ts @@ -22,17 +22,15 @@ cypress.run().then(results => { cypress.open() // $ExpectType Promise cypress.run() // $ExpectType Promise -cypress.open({ - configFile: false -}) - cypress.run({ configFile: "abc123" }) // provide only some config options const runConfig: Cypress.ConfigOptions = { - baseUrl: 'http://localhost:8080', + e2e: { + baseUrl: 'http://localhost:8080', + }, env: { login: false }, diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index eecb36f659..1d6296adab 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -33,9 +33,11 @@ namespace CypressConfigTests { Cypress.config().baseUrl // $ExpectType string | null // setters - Cypress.config('baseUrl', '.') // $ExpectType void - Cypress.config('baseUrl', null) // $ExpectType void - Cypress.config({ baseUrl: '.', }) // $ExpectType void + Cypress.config({ e2e: { baseUrl: '.' }}) // $ExpectType void + Cypress.config({ e2e: { baseUrl: null }}) // $ExpectType void + Cypress.config({ e2e: { baseUrl: '.', }}) // $ExpectType void + Cypress.config({ component: { baseUrl: '.', devServer: () => ({} as any) } }) // $ExpectError + Cypress.config({ e2e: { indexHtmlFile: 'index.html' } }) // $ExpectError Cypress.config('taskTimeout') // $ExpectType number Cypress.config('includeShadowDom') // $ExpectType boolean @@ -798,7 +800,6 @@ namespace CypressTestConfigOverridesTests { // set config on a per-test basis it('test', { animationDistanceThreshold: 10, - baseUrl: 'www.foobar.com', defaultCommandTimeout: 6000, env: {}, execTimeout: 6000, @@ -859,7 +860,6 @@ namespace CypressTestConfigOverridesTests { // set config on a per-suite basis describe('suite', { browser: {family: 'firefox'}, - baseUrl: 'www.example.com', keystrokeDelay: 0 }, () => {}) @@ -867,7 +867,6 @@ namespace CypressTestConfigOverridesTests { describe('suite', { browser: {family: 'firefox'}, - baseUrl: 'www.example.com', keystrokeDelay: false // $ExpectError foo: 'foo' // $ExpectError }, () => {}) diff --git a/cli/types/tests/plugins-config.ts b/cli/types/tests/plugins-config.ts index 07edfa000e..2292a8e42f 100644 --- a/cli/types/tests/plugins-config.ts +++ b/cli/types/tests/plugins-config.ts @@ -6,15 +6,14 @@ const pluginConfig: Cypress.PluginConfig = (on, config) => {} // allows synchronous returns const pluginConfig2: Cypress.PluginConfig = (on, config) => { config // $ExpectType PluginConfigOptions - config.baseUrl // $ExpectType string | null - config.configFile // $ExpectType string | false + config.configFile // $ExpectType string config.fixturesFolder // $ExpectType string | false - config.pluginsFile // $ExpectType string | false config.screenshotsFolder // $ExpectType string | false config.videoCompression // $ExpectType number | false config.projectRoot // $ExpectType string config.version // $ExpectType string config.testingType // $ExpectType TestingType + config.browsers // $ExpectType Browser[] on('before:browser:launch', (browser, options) => { browser.displayName // $ExpectType string @@ -66,7 +65,9 @@ const pluginConfig2: Cypress.PluginConfig = (on, config) => { }) return { - baseUrl: 'http://localhost:3000' + e2e: { + baseUrl: 'http://localhost:3000' + } } } @@ -105,7 +106,9 @@ const pluginConfig4: Cypress.PluginConfig = (on, config) => { }) return Promise.resolve({ - baseUrl: 'http://localhost:3000' + e2e: { + baseUrl: 'http://localhost:3000' + } }) } diff --git a/graphql-codegen.yml b/graphql-codegen.yml new file mode 100644 index 0000000000..c70f4e72a2 --- /dev/null +++ b/graphql-codegen.yml @@ -0,0 +1,127 @@ +# https://www.graphql-code-generator.com/docs/getting-started/index + +documentFilters: &documentFilters + immutableTypes: true + useTypeImports: true + preResolveTypes: true + onlyOperationTypes: true + avoidOptionals: true + +vueOperations: &vueOperations + schema: './packages/graphql/schemas/schema.graphql' + config: + <<: *documentFilters + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript' + - 'typescript-operations' + - 'typed-document-node': + # Intentionally specified under typed-document-node rather than top level config, + # becuase we don't want it flattening the types for the operations + flattenGeneratedTypes: true + +vueTesting: &vueTesting + schema: './packages/graphql/schemas/schema.graphql' + config: + <<: *documentFilters + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript' + - 'typescript-operations': + # For modifying in mountFragment + immutableTypes: false + - 'typed-document-node' + +overwrite: true +config: + enumsAsTypes: true + declarationKind: 'interface' + strictScalars: true + scalars: + Date: string + DateTime: string + JSON: any +generates: + ### + # Generates types for us to infer the correct "source types" when we mock out on the frontend + # This ensures we have proper type checking when we're using cy.mountFragment in component tests + ### + './packages/frontend-shared/cypress/support/generated/test-graphql-types.gen.ts': + schema: 'packages/graphql/schemas/schema.graphql' + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript': + nonOptionalTypename: true + - 'packages/frontend-shared/script/codegen-type-map.js' + + './packages/frontend-shared/cypress/support/generated/test-cloud-graphql-types.gen.ts': + schema: 'packages/graphql/schemas/cloud.graphql' + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript': + nonOptionalTypename: true + - 'packages/frontend-shared/script/codegen-type-map.js' + + './packages/graphql/src/gen/cloud-source-types.gen.ts': + schema: 'packages/graphql/schemas/cloud.graphql' + plugins: + - add: + content: '/* eslint-disable */' + - 'typescript' + + ### + # Generates types for us to infer the correct keys for graphcache + ### + './packages/data-context/src/gen/graphcache-config.gen.ts': + config: + useTypeImports: true + schema: 'packages/graphql/schemas/schema.graphql' + plugins: + - add: + content: '/* eslint-disable */' + - typescript + - typescript-urql-graphcache + + ### + # All of the GraphQL Query/Mutation documents we import for use in the .{vue,ts,tsx,js,jsx} + # files for useQuery / useMutation, as well as types associated with the fragments + ### + './packages/launchpad/src/generated/graphql.ts': + documents: + - './packages/launchpad/src/**/*.{vue,ts,tsx,js,jsx}' + - './packages/frontend-shared/src/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueOperations + + './packages/app/src/generated/graphql.ts': + documents: + - './packages/app/src/**/*.{vue,ts,tsx,js,jsx}' + - './packages/frontend-shared/src/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueOperations + + './packages/frontend-shared/src/generated/graphql.ts': + documents: './packages/frontend-shared/src/gql-components/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueOperations + ### + # All GraphQL documents imported into the .spec.tsx files for component testing. + # Similar to generated/graphql.ts, except it doesn't include the flattening for the document nodes, + # so we can actually use the document in cy.mountFragment + ### + './packages/launchpad/src/generated/graphql-test.ts': + documents: + - './packages/launchpad/src/**/*.{vue,ts,tsx,js,jsx}' + - './packages/frontend-shared/src/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueTesting + + './packages/app/src/generated/graphql-test.ts': + documents: + - './packages/app/src/**/*.{vue,ts,tsx,js,jsx}' + - './packages/frontend-shared/src/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueTesting + + './packages/frontend-shared/src/generated/graphql-test.ts': + documents: './packages/frontend-shared/src/gql-components/**/*.{vue,ts,tsx,js,jsx}' + <<: *vueTesting diff --git a/guides/app-lifecycle.md b/guides/app-lifecycle.md new file mode 100644 index 0000000000..5ae11b8795 --- /dev/null +++ b/guides/app-lifecycle.md @@ -0,0 +1,80 @@ +## App Lifecycle + +This documents the lifecycle of the application, specifically related to managing the current project, +and the various states & inputs that can feed into state changes, and how they are managed + +1. Application starts via `cypress open | run --flags` + 1. The input is run through `cli/lib/cli.js` for normalization + 1. The normalized input is passed into the server, eventually getting to `server/lib/modes/index.ts` +1. The `DataContext` class receives the testing mode (`run` | `open`), and the `modeOptions` (CLI Flags) +1. We call `ctx.initialize`, which based on the `mode` returns a promise for series of steps needed + 1. The `DataContext` should act as the global source of truth for all state in the application. It should be passed along where possible. In the `server` package, we can import/use `getCtx` so we don't need to pass it down the chain. + 1. The CLI flags & environment variables are used set the initial state of the `coreData` + 1. TODO: rename to `appState`? + 1. In `open` mode, if the `--global` flag is passed, we start in "global" mode, which allows us to select multiple projects + 1. Once a project is selected, either via the CLI being run within a project, or via the `--project` flag, we launch into project mode + +## Project Lifecycle + +1. Once a project is selected, we source the config from `cypress.config.js`, or wherever the config is specified via the `--configFile` CLI flag: + 1. Read the `globalBrowsers` + 1. Execute the `configFile` in a child process & reply back with the config, and the require.cache files in the child process + 1. If there is an error sourcing the config file, we set an error on the `currentProject` in the root state + 1. We source `cypress.env.json` and validate (if it exists) + +## **Config Precedence:** + +1. Runtime, inline: `it('should do the thing', { retries: { run: 3 } }` +2. `port` from spawned server +3. Returned from `setupNodeEvents` (as these get the options from the CLI) +4. Sourced from CLI +5. Sourced from `cypress.env.json` +6. Sourced from `cypress.config.{js|ts}` +7. Default config options + +## **Merging** + +Config options are deeply merged: + +```bash +# CLI: +cypress run --env FOO=bar + +# cypress.config.js +env: { + FOO: 'test' +}, +e2e: { + setupNodeEvents (on, config) { + return require('@cypress/code-coverage')(on, config) + }, + env: { + e2eRunner: true + } +} + +# Would Result in + +{ + env: { FOO: 'bar', e2eRunner: true } +} +``` + +## Steps of Sourcing / Execution + +1. **Application Start** + 1. CLI args & environment are parsed into an "options" object, which is passed along to create the initial application config + 2. Browsers are sourced from the machine at startup + 3. CLI options `--config baseUrl=http://example.com`, `--env` are gathered for merging later + 1. [https://gist.github.com/tgriesser/5111edc0e31b9db61755b0bddbf93e78](https://gist.github.com/tgriesser/5111edc0e31b9db61755b0bddbf93e78) +2. **Project Initialization** + 1. When we have a "projectRoot", we execute the `cypress.config.{js|ts}`, and read the `cypress.env.json` - this will be persisted on the state object, so we can compare the diff as we detect/watch changes to these files + 1. The child process will also send back a list of files that have been sourced so we can watch them for changes to re-execute the config. *We may want to warn against importing things top-level, so as to minimize the work done in child-process blocking the config* + 2. We also pull the "saved state" for the user from the FS App data + 1. We only do this in "open mode" + 3. At this point, we do a first-pass at creating a known config shape, merging the info together into a single object, picking out the "allowed" list of properties to pass to the `setupNodeEvents` +3. **setupNodeEvents** + 1. Once we have selected a `testingType`, we execute the `setupNodeEvents`, passing an "allowed" list of options as the second argument to the function. At this point, we have merged in any CLI options, env vars, + 1. If they return a new options object, we merge it with the one we passed in +4. **config โ†’ FullConfig** + 1. At this point we have the entire config, and we can set the `resolved` property which includes the origin of where the config property was resolved from diff --git a/guides/e2e-open-testing.md b/guides/e2e-open-testing.md new file mode 100644 index 0000000000..e68c9b7278 --- /dev/null +++ b/guides/e2e-open-testing.md @@ -0,0 +1,60 @@ +# E2E Open Mode Testing + +The "Open Mode" E2E tests in `packages/app` & `packages/launchpad` are the "system tests" for the open mode. This means that they hit the actual node server and act as a realistic "real world" scenario as much as possible. The main idea of these tests is to act as comprehensive "end-to-end" test for the actual server execution, and act as a "black box", testing for functional behavior as high-level as possible - only tapping into lower-level details when it's necessary. + +### Example Test: + +```ts +beforeEach(() => { + // Scaffold a project, from system-tests/fixtures + cy.scaffoldProject('todos') + + // "Open" the project, as though you did cypress open --project 'path/to/todos' + cy.openProject('todos') + + // Open the project, passing '--e2e' in the argv for cypress open + cy.openProject('todos', ['--e2e']) + + // cypress open --global + cy.openGlobalMode() +}) + +it('should onboard a todos project', () => { + cy.visitLaunchpad() + cy.get('[e2e-project]').click() + cy.withCtx(async (ctx) => { + await ctx.actions.file.writeFileInProject('cypress.config.ts', 'export default {}') // Adds a file + }) +}) +``` + +### Testing the App: + +```ts +it('should open todos in the app', () => { + cy.startAppServer() // starts the express server used to run the "app" + cy.visitApp() // visits the app page, without launching the browser + cy.get('[href=#/runs]').click() + cy.get('[href=#/settings]').click() +}) +``` + +### Remote GraphQL Schema Mocking + +When we hit the remote GraphQL server, we mock against the same mocked schema we use client-side in the component tests. If we want to modify these responses we can use `cy.remoteGraphQLIntercept` to tap in and modify the mocked payloads to simulate different states: + +```ts +cy.remoteGraphQLIntercept(async (obj) => { + // Currently, all remote requests go through here, we want to use this to modify the + // remote request before it's used and avoid touching the login query + if (obj.result.data?.cloudProjectsBySlugs) { + for (const proj of obj.result.data.cloudProjectsBySlugs) { + if (proj.runs?.nodes) { + proj.runs.nodes = [] + } + } + } + + return obj.result +}) +``` diff --git a/guides/error-handling-accept-snapshot.png b/guides/error-handling-accept-snapshot.png new file mode 100644 index 0000000000..f3be3fa5f9 Binary files /dev/null and b/guides/error-handling-accept-snapshot.png differ diff --git a/guides/error-handling.md b/guides/error-handling.md index 486073673a..3035e33c32 100644 --- a/guides/error-handling.md +++ b/guides/error-handling.md @@ -6,11 +6,38 @@ Clear, consistent, errors are one of the important parts of the Cypress experien All error related logic for the server should be added to `@packages/errors`. This logic has been separated out from the `@packages/server` to enable strict type checking & use in other packages we have added in the `10.0-release` branch. -Summary of the Errors package: +### Errors Development Workflow -- `errors.ts`: A key/value mapping of known errors to functions returning "ErrorTemplates", described below, also includes/re-exports several helper utilities: +Adding and editing errors is best done with the help of the Error Comparison tool. + +Start off by launching the Error Comparison tool from `packages/errors` via `yarn comparison`. This will launch a mini-webapp at http://localhost:5555. + +The Error Comparison app has three pages: Ansi Compare, Ansi Base List, and Markdown. + +1. Ansi Compare - Used to compare and accept changes made during development +2. Ansi Base List - Used to preview errors as they will be rendered to users in the Terminal. +3. Markdown - Used to preview errors as they will be rendered to users within the App, Launchpad, and Reporter. + +#### Editing or Adding New Errors and Updating Snapshots + + + +1. Add (or update) errors in `packages/errors/src/errors.ts` +2. Add test cases to `visualSnapshotErrors_spec.ts` +3. Run `yarn test` in the `packages/errors` directory +4. Run `yarn comparison` in the `packages/errors` directory +5. Open http://localhost:5555/ +6. Search for the error you're working on by the error key. (e.g. `AUTOMATION_SERVER_DISCONNECTED`) +7. Click "Looks Good" if it looks good. +8. To make edits, re-run the `yarn test` command and do a full refresh of the webapp. +9. Run `yarn test` after updating the snapshot to validate the changes were applied. +10. Commit the files changed in `__snapshot-html__` + +### Technical Overview + +- `errors.ts`: A key/value mapping of known errors to functions returning "ErrorTemplates", described below, also includes/re-exports several helper utilities: - `get` / `getError`: builds & retrieves the error as a `CypressError`, should be the main way we retrieve errors throughout Cypress. Aliased as `errors.get` for existing use in the server package - - `throw` / `throwErr`: Get & throw the error, so we can spy/stub it in a test. Aliased as `errors.throw` for existing use in the server package + - `throw` / `throwErr`: Get & throw the error, so we can spy/stub it in a test. Aliased as `errors.throwErr` for existing use in the server package - `logWarning`: Logs the error as a warning to the console, aliased as `errors.log` for existing use in the server package - `errTemplate.ts`: Tagged template literal formatting the error as described below - `stackUtils.ts`: Utilities for working with a stack trace, extended by the driver package @@ -26,9 +53,9 @@ Return Value of `errTemplate` (`ErrTemplateResult`): ```ts { // Will always exist, this is the terminal-formatted error message - message: string, + message: string, // Will always exist, this is the browser-formatted error message - messageMarkdown: string, + messageMarkdown: string, details?: string, // Exists if there is `details()` call in the errTemplate originalError?: ErrorLike // Exists if an error was passed into the `details()` } @@ -44,7 +71,7 @@ CANNOT_TRASH_ASSETS: (arg1: string) => { This error will not alter the exit code. ${details(arg1)}` -}, +}, ``` In this case, `arg1` will be highlighted in yellow when printed to the terminal. @@ -70,7 +97,7 @@ PLUGINS_FILE_ERROR: (arg1: string, arg2: Error) => { ### Error Wrapping -Any time we know about an edge case that is an error, we should define an error in `errors.ts`. This error should be retrieved by `getError`, which converts it to a `CypressError`. +Any time we know about an edge case that is an error, we should define an error in `errors.ts`. This error should be retrieved by `getError`, which converts it to a `CypressError`. The `CypressError` is an `Error` containing the message returned from the `errTemplate`. The `stack` is set to that of the `originalError` if it exists (i.e. the error object passed into `details`), otherwise it's the `stack` from where the `getError` / `throwError` is called. @@ -79,7 +106,6 @@ The `CypressError` has an `isCypressErr` prop which we use as a duck-type guard ### Child-Process Errors -All errors that occur in a child process spawned by Cypress should be sent over the `ipc` bridge using `util.serializeError`. - -This ensures the `name`, `message`, `stack`, and any other relevant details are preserved and can be handled by the standard process of Cypress' error standardization / wrapping. +All errors that occur in a child process spawned by Cypress should be sent over the `ipc` bridge using `util.serializeError`. +This ensures the `name`, `message`, `stack`, and any other relevant details are preserved and can be handled by the standard process of Cypress' error standardization / wrapping. \ No newline at end of file diff --git a/guides/graphql-subscriptions.md b/guides/graphql-subscriptions.md new file mode 100644 index 0000000000..47ba0a66f5 --- /dev/null +++ b/guides/graphql-subscriptions.md @@ -0,0 +1,119 @@ +## GraphQL Subscriptions Overview & Test Guide: + +In GraphQL there are currently 3 types of Operations: `query`, `mutation`, `subscription` + +Query is similar to a rest-ful `GET` request: + +```graphql +query MyAppData { + cloudUser { # CloudUser type + id + email + fullName + } + currentProject { # Project type + id + name + ...CurrentProjectCard + } + app { # App type + localSettings { + ...LocalSettingsView + } + } +} +``` + +Whereas a mutation is like a `POST` request, where you ask for what you want back (what changed b/c of the mutation): + +```graphql +mutation MyAppMutation($testingType: TestingTypeEnum) { + chooseTestingType(testingType: $testingType) { # Project type + id + currentTestingType + } +} +``` + +A subscription is used when you want to receive information about data that has changed scoped to an individual event: + +```graphql +subscription MyAppSubscription { + projectUpdated { # Project type + id + isLoadingConfig + isLoadingSetupNodeEvents + } +} +``` + +The distinction between subscriptions & queries is that subscriptions can only have a single top-level field. You can think of the subscription like an "event name" in socket.io, except that it's strongly typed & part of the overall GraphQL schema, meaning that you don't need to do any extra work for it to merge into the normalized cache & refresh affected parts of the view. + +```ts +// will merge & update any views that depend on `isLoadingConfig` / `isLoadingSetupNodeEvents` +useSubscription({ query: MyAppSubscriptionDocument }) +``` + +We can also use subscriptions more granularly as an event emitter, basically as a strongly typed socket.io emitter: + +```graphql +subscription OnSpecChange { + onSpecUpdate { + specPath + reason + } +} +``` + +```ts +useSubscription({ query: OnSpecChangeDocument }, (prev, next) => { + if (data.specPath === currentSpecPath && reason === 'DELETED') { + // navigate to another page + } else { + // Rerun spec + } + return next +}) +``` + +### Client Details: + +- [API Docs for useSubscription](https://formidable.com/open-source/urql/docs/api/vue/#usesubscription) +- [Subscriptions overview](https://formidable.com/open-source/urql/docs/advanced/subscriptions/) + +One thing to be aware of, is the subscription is only mounted/responded to when the containing component is mounted on the page. Therefore, one rule of thumb when using subscriptions is to ensure that they are declared in the subscription dependent view that is highest in the hierarchy so that the subscription can be active when it needs to be. This location is often alongside a query rather than a fragment. + + +### Server Docs + +Subscriptions are implemented on the server as an `AsyncIterator`. This is handled for us by the [graphql-ws](https://github.com/enisdenjo/graphql-ws) package. + +To add a new Subscription field, add a new entry in the [`gql-Subscriptions`](../packages/graphql/src/schemaTypes/objectTypes/gql-Subscription.ts): + +```ts +t.field('browserStatusChange', { + type: CurrentProject, + description: 'Status of the currently opened browser', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('browserStatusChange'), + resolve: (source, args, ctx) => ({}), +}) +``` + +And then add the corresponding method in [DataEmitterActions](../packages/data-context/src/actions/DataEmitterActions.ts) + + +```ts +browserStatusChange () { + this._emit('browserStatusChange') +} +``` + +- [API Docs](https://github.com/enisdenjo/graphql-ws/tree/master/docs) +- [Transport layer protcol specification](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) + +### Testing + +If you want to TDD the subscription being added & working directly in isolation, one recommended approach is to add one spec file per-subscription in the `/app/cypress/e2e/subscription` directory. This file can cover both the app & launchpad handling of a given subscription. + +Example: [authChange-subscription.cy.ts](../packages/app/cypress/e2e/subscriptions/authChange-subscription.cy.ts) + diff --git a/guides/testing-strategy-and-styleguide.md b/guides/testing-strategy-and-styleguide.md new file mode 100644 index 0000000000..cd93e5f98d --- /dev/null +++ b/guides/testing-strategy-and-styleguide.md @@ -0,0 +1,154 @@ +# DRAFT - CYPRESS TESTING STRATEGY + STYLE GUIDE +## Status of this document + +This draft is a starting point to help us converge on some common practices in terms of how we write tests, and a reference point for how we can review test PRs with each other. There are many valid style choices to make in writing tests, and some of them are contradictory, so a consistent approach is useful. + +I'm starting by documenting the practices that I see us currently doing in the new parts of the codebase, or things we seem to have agreed we'd like to do. Not exhaustive, and not prescriptive. The Testing Strategy section existed already in Google Docs. + +## Testing Strategy +The purpose of this document is to detail the various ways to test the cypress repo including the Cypress App. + +### Testing Goals +The goal of testing is to instill confidence in the features being built and the bugs being fixed as well as save development hours. + +Test driven development (TDD) is a core tenet to how we write tests at Cypress. Our approach is to Shift-left testing whenever possible. + +### Testing Types +- Unit - Tests the functionality of a single section of code, like a single function. +- Integration - Tests the functionality of a feature, with some portions (like a backend) mocked. +- End-to-end (E2E) - Tests the functionality of a feature with no mocking. It tests all pieces of the feature working together. +- Component - Tests a single component or group of components. +- System - A type of E2E test that tests an entire project in the context of Cypress. +- Snapshot - Captures text output and compares them to previously captured text output (like testing output for a CLI). +- Screenshot - Captures screenshots and compares them to previously captured screenshots. +- Performance - Tests the speed, response time, stability, reliability, scalability and resource usage of the application. + +### Testing Environments +Tests can run in different environments: + +- Different browsers +- Different OSs +- Node.js + +### Testing Tools +- Mocha +- Cypress +- Snapshot tests using [snap-shot-it](https://github.com/bahmutov/snap-shot-it) - Use `SNAPSHOT_UPDATE=1 ` to update them, but make sure to check the diff to ensure it's the right update. +- Percy snapshot tests - These only run in CI and can be managed from the GitHub status check on a PR + +### Testing Workflow +Developing features and fixing bugs should be test driven. + +An example of building out a front-end facing feature may go like this: + +1. Check user requirements in the ticket/issue youโ€™re assigned to. +1. Write a failing component test for a features required in the user story. +1. Build the piece of the component needed so that the failing test passes. +1. Repeat steps 2-3 until the component satisfies the user requirements. +1. Write out all CSS required for the feature to be design complete. +1. Add a screenshot test. +1. Write an E2E test to ensure all pieces and integrations work together. +1. Add performance tests if necessary to ensure the feature doesnโ€™t introduce regressions on performance. + +An example of building out a feature/change to the CLI may go like this: + +1. Check user requirements in the ticket/issue youโ€™re assigned to. +1. Write a failing unit/integration test for the feature required in the user story.1. Write the logic for the new feature/change. +1. Capture/update a snapshot test for any changes to the printed console output. + + +## Component and E2E Tests in App, Launchpad, and Frontend-Shared Packages + +### Component Tests +Component tests should assert all expected behaviors of a component from a user perspective, as well as the "contract" of the component from a developer perspective. It is useful to write component tests as the primary driver of component development. This helps with development speed (no need to keep getting the whole app into the state you want), and test completeness. + +For user-facing behavior, we interact with (or remount) the component to get it into all desired states and confirm they are valid. Each state should have a Percy snapshot in addition to regular Cypress assertions. + +For developer-facing behavior - props received, events emitted, any other side effects, anything not covered in the UI tests can be explicitly asserted on its own. Props are often fully covered by UI assertions, but events emitted by the component to be used in parent components are not. So we can stub event handlers and verify that they are called in response to particular interactions. + +**Many components** in the unified App and Launchpad define the data they require from GraphQL with a Fragment inside the component's `script` section, and receive the data from that Fragment in a prop called `gql`, so mocking out scenarios usually involves tweaking the mocked GraphQL data before the component mounts using `mountFragment()`. + +### E2E Tests +Certain side effects, like GraphQL mutations, do not fire from component tests, but can be monitored from an E2E test with `cy.intercept`. And some entire packages, like `reporter` are independent apps that can be mounted in an E2E test and tested for interactions with other parts of the system. + +## Testing Style Guide + +### String constants +Strings used in tests for locating elements or asserting content in other ways are imported from the i18n constants. All strings present in the App or Launchpad UI should be found in some form in `en-US.json`. If a plain string is found in the UI code (we have a few of them), it should be moved into the constants file and then imported to both the component and the test code. + +### Element Locators +When relevant, element locators can assert something useful about the nature or context of the element in the DOM. Often for accessibility reasons it is important what elements are rendered. If there is nothing in particular that matters about the DOM, or if needed to disambiguate, then `data-cy` attributes can be used to locate elements. + +### Testing Interactive Elements +If the test will interact with an element, or assert the state of an interactive element, **always prefer to locate that element with its accessible name** (and, usually, an assertion about the element itself). Without an accessible name, the element will not be described correctly by a screen reader, which means certain disabled users would not know what the control or form field is for. Since we want every user to be able to interact with our app, a test that interacts with something should fail if there is no label for it. + +Examples: + +```js +cy.contains('button', 'Log In').click() +``` + +```js +cy.findByLabelText('open navigation', { + selector: 'button', + }).click() +``` + +#### Label-like locators that are not labels + +We should be cautious with a locator like `cy.findByPlaceholderText('My placeholder')` to target a form input, as an input that only has a `placeholder`, but no `label`, is not fully accessible. Even though it may be useful to assert the placeholder contents for its own sake, we should prefer to locate an input by `label` when interacting. + +### Non-interactive elements +When assertions are made against non-interactive elements, if the surrounding HTML is relevant from an accessibility perspective, assert the relevant parts of the HTML: + +```js +cy.contains('h1', 'Page Title!').should('be.visible') +``` +```js +cy.contains('h2', 'Modal Title').should('be.visible') +``` + +This is a judgement call, there is a spectrum between asserting useful things about the DOM and writing a brittle assertion like this that adds no value to the test: + +```js +cy.contains('div > div > .special-list > li > span', 'Home Link')` +``` + +In general, prefer to limit assertions about the nature of the DOM to a small surface area near the target element. Even then, only assert the DOM if there is a reason that changing the DOM in that area would harm the use experience - for example by breaking accessibility. + +### Data-cy attributes + +Sometimes the specific details of an element don't matter so we don't assert what kind of element it is. Or the contents are dynamic and can't be controlled in the test, so we can't use the content to locate the element. In these cases `data-cy` attributes can be used: + +``` +cy.get('[data-cy="success-toast"]').should('be.visible') // just make sure it exists +``` + +`data-cy` can also be combined with other selectors to help target a specific element we've identified in our code, while continuing to assert the appropriate DOM and content: + +``` +cy.contains('[data-cy="success-toast"] h2', 'Success!').should('be.visible') // toast with correct heading element and test exists +``` + +Be cautious when using _only_ `data-cy` to locate an element, because doing so specifically tells the test not to care about what kind of element it is, or what it contains. So we should be sure that's what is intended. This means we should rarely, if ever, rely on `data-cy` alone to locate an element we will interact with. It should always be combined with an assertion about the label/name of that element. + +An exception would be when testing a something like card in the UI, if the whole card is supposed to be clickable. While there should be some focusable element inside the card for keyboard and screenreader users, the card itself does not need a label but should still be tested, alongside the properly labelled accessible control for the same function: + +``` +cy.get('[data-cy="ui-card"]').click() // test clicking at the level of the card itself +// ... assert expected state ... + +cy.contains('[data-cy="ui-card"] button', 'Activate').click() // test the accessible trigger for that card's functionality +// ... assert expected state ... + +``` + +### Visibility Checks + +Asserting `should('be.visible')` is useful when testing elements that the test won't interact with, as in certain situations it is possible for elements to be found in the DOM with the content we expect, but to still be unexpectedly hidden from the user with CSS or covered by another element. When interacting, that visibility check is already built in before `cy.click` or `cy.type` for example. + +### Cypress-Testing-Library +Feel free to use this often in tests if it makes the test easier to write or understand, except where using it provides less confidence than a plain Cypress selector. For example `cy.contains('button', 'Log In')` is slightly preferred to `cy.findByRole('button', {name: 'Log In' })`, because the ARIA role of `button` could be added to an element that does not have the expected keyboard behaviors implemented, and the test might still pass. It is also a good accessibility practice to not use ARIA to recreate the existing functionality of HTML elements, but instead use the elements directly. So using `findByRole` should not be necessary except for certain UI interactions like tabs or carousels, if we have those. + +### Visual Appearance +Avoid specifying specific CSS color values in tests. Prefer Percy snapshots to validate that the approved appearance isn't changing unexpectedly. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000000..2d9b050637 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,2 @@ +require('@packages/ts/register') +require('./scripts/gulp/gulpfile') diff --git a/npm/angular/README.md b/npm/angular/README.md index 4455fcafaa..efb22a59c9 100644 --- a/npm/angular/README.md +++ b/npm/angular/README.md @@ -14,7 +14,7 @@ Ensure you have a version of Cypress > 7. Add the following to your support file: ```js -// cypress/support/index.js +// cypress/support/component.js // core-js 3.* require('core-js/es/reflect'); // core-js 2.* @@ -22,13 +22,12 @@ require('core-js/es7/reflect'); require('@cypress/angular/support'); ``` -Enable component testing in `cypress.json`. +Enable component testing in `cypress.config.js`. -```json -{ +```js +module.exports = { "component": { - "componentFolder": "src/app", - "testFiles": "**/*cy-spec.ts" + "specPattern": "src/**/*.cy.ts" } } ``` @@ -156,15 +155,21 @@ module.exports = { `npm install -D @cypress/code-coverage` -- Then add the code below to your supportFile and pluginsFile +- Then add the code below to your component support file ```javascript -// cypress/support/index.js import '@cypress/code-coverage/support'; -// cypress/plugins/index.js -module.exports = (on, config) => { - require('@cypress/code-coverage/task')(on, config); - return config; +``` +- Then add the code below to your cypress configuration +```js +{ + ... + component: { + setupNodeEvents(on, config) { + require('@cypress/code-coverage/task')(on, config); + return config; + } + } }; ``` diff --git a/npm/angular/cypress.config.ts b/npm/angular/cypress.config.ts new file mode 100644 index 0000000000..ca832c23fd --- /dev/null +++ b/npm/angular/cypress.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'cypress' +import { devServer } from '@cypress/webpack-dev-server' +import * as webpackConfig from './cypress/plugins/webpack.config' + +export default defineConfig({ + 'experimentalFetchPolyfill': true, + 'fixturesFolder': false, + 'includeShadowDom': true, + 'fileServerFolder': 'src', + 'projectId': 'nf7zag', + 'component': { + setupNodeEvents (on, config) { + return require('./cypress/plugins')(on, config) + }, + devServer, + devServerConfig: { webpackConfig }, + }, +}) diff --git a/npm/angular/cypress.json b/npm/angular/cypress.json deleted file mode 100644 index ebe21a31c3..0000000000 --- a/npm/angular/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "experimentalFetchPolyfill": true, - "fixturesFolder": false, - "includeShadowDom": true, - "fileServerFolder": "src", - "projectId": "nf7zag", - "component": { - "componentFolder": "src/app", - "testFiles": "**/*cy-spec.ts" - } -} diff --git a/npm/angular/cypress/integration/cy-spec.ts b/npm/angular/cypress/e2e/spec.cy.ts similarity index 100% rename from npm/angular/cypress/integration/cy-spec.ts rename to npm/angular/cypress/e2e/spec.cy.ts diff --git a/npm/angular/cypress/plugins/index.ts b/npm/angular/cypress/plugins/index.ts index 19515cec72..703cf4278f 100644 --- a/npm/angular/cypress/plugins/index.ts +++ b/npm/angular/cypress/plugins/index.ts @@ -1,16 +1,7 @@ import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin' -import * as webpackConfig from './webpack.config' module.exports = (on, config) => { addMatchImageSnapshotPlugin(on, config) - const { startDevServer } = require('@cypress/webpack-dev-server') - - on('dev-server:start', (options) => { - return startDevServer({ - options, - webpackConfig, - }) - }) require('@cypress/code-coverage/task')(on, config) diff --git a/npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy-spec.ts/clicked.snap.png b/npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy.ts/clicked.snap.png similarity index 100% rename from npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy-spec.ts/clicked.snap.png rename to npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy.ts/clicked.snap.png diff --git a/npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy-spec.ts/init.snap.png b/npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy.ts/init.snap.png similarity index 100% rename from npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy-spec.ts/init.snap.png rename to npm/angular/cypress/snapshots/app/image-snapshot/image-snapshot.component.cy.ts/init.snap.png diff --git a/npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy-spec.ts/clicked.snap.png b/npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy.ts/clicked.snap.png similarity index 100% rename from npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy-spec.ts/clicked.snap.png rename to npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy.ts/clicked.snap.png diff --git a/npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy-spec.ts/init.snap.png b/npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy.ts/init.snap.png similarity index 100% rename from npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy-spec.ts/init.snap.png rename to npm/angular/cypress/snapshots/image-snapshot/image-snapshot.component.cy.ts/init.snap.png diff --git a/npm/angular/cypress/support/component-index.html b/npm/angular/cypress/support/component-index.html new file mode 100644 index 0000000000..5f9622ae29 --- /dev/null +++ b/npm/angular/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + diff --git a/npm/angular/cypress/support/index.ts b/npm/angular/cypress/support/component.ts similarity index 100% rename from npm/angular/cypress/support/index.ts rename to npm/angular/cypress/support/component.ts diff --git a/npm/angular/cypress/tsconfig.json b/npm/angular/cypress/tsconfig.json index e9dbbf8a93..d993a14627 100644 --- a/npm/angular/cypress/tsconfig.json +++ b/npm/angular/cypress/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["integration/*.ts"], + "include": ["e2e/*.ts"], "compilerOptions": { "emitDecoratorMetadata": true, "experimentalDecorators": true, diff --git a/npm/angular/package.json b/npm/angular/package.json index ac8e63ff17..b91fcc72d2 100644 --- a/npm/angular/package.json +++ b/npm/angular/package.json @@ -7,13 +7,14 @@ "scripts": { "build": "tsc --project tsconfig.lib.json", "watch": "tsc --project tsconfig.lib.json -w", - "cy:open": "node ../../scripts/cypress.js open-ct", - "cy:run": "node ../../scripts/cypress.js run-ct", + "cy:open": "node ../../scripts/cypress.js open --component", + "cy:run": "node ../../scripts/cypress.js run --component", "ng": "ng", "app-start": "ng serve", "app-build": "ng build", "test": "yarn cy:run", - "test-ci": "yarn cy:run" + "test-ci": "yarn cy:run", + "postinstall": "patch-package" }, "dependencies": { "@cypress/mount-utils": "0.0.0-development", @@ -59,7 +60,7 @@ "semantic-release": "17.4.2", "to-string-loader": "1.1.6", "ts-loader": "8.1.0", - "ts-node": "9.1.1", + "ts-node": "^10.2.1", "tslib": "^2.2.0", "tslint": "5.20.1", "typescript": "4.2.4", diff --git a/npm/angular/patches/@cypress+code-coverage+3.9.5.patch b/npm/angular/patches/@cypress+code-coverage+3.9.5.patch new file mode 100644 index 0000000000..f905d3a539 --- /dev/null +++ b/npm/angular/patches/@cypress+code-coverage+3.9.5.patch @@ -0,0 +1,45 @@ +diff --git a/node_modules/@cypress/code-coverage/support-utils.js b/node_modules/@cypress/code-coverage/support-utils.js +index 31e00ee..0c56908 100644 +--- a/node_modules/@cypress/code-coverage/support-utils.js ++++ b/node_modules/@cypress/code-coverage/support-utils.js +@@ -10,7 +10,7 @@ const filterSpecsFromCoverage = (totalCoverage, config = Cypress.config) => { + const integrationFolder = config('integrationFolder') + /** @type {string} Cypress run-time config has test files string pattern */ + // @ts-ignore +- const testFilePattern = config('testFiles') ++ const testFilePattern = config('specPattern') + + // test files chould be: + // wild card string "**/*.*" (default) +diff --git a/node_modules/@cypress/code-coverage/support.js b/node_modules/@cypress/code-coverage/support.js +index c99ceb2..f51ce4e 100644 +--- a/node_modules/@cypress/code-coverage/support.js ++++ b/node_modules/@cypress/code-coverage/support.js +@@ -37,7 +37,6 @@ const logMessage = (s) => { + * If there are more files loaded from support folder, also removes them + */ + const filterSupportFilesFromCoverage = (totalCoverage) => { +- const integrationFolder = Cypress.config('integrationFolder') + const supportFile = Cypress.config('supportFile') + + /** @type {string} Cypress run-time config has the support folder string */ +@@ -50,16 +49,9 @@ const filterSupportFilesFromCoverage = (totalCoverage) => { + isSupportFile(filename) + ) + +- // check the edge case +- // if we have files from support folder AND the support folder is not same +- // as the integration, or its prefix (this might remove all app source files) +- // then remove all files from the support folder +- if (!integrationFolder.startsWith(supportFolder)) { +- // remove all covered files from support folder +- coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => +- filename.startsWith(supportFolder) +- ) +- } ++ coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => ++ filename.startsWith(supportFolder) ++ ) + return coverage + } + diff --git a/npm/angular/src/app/add-style/add-style.component.cy-spec.ts b/npm/angular/src/app/add-style/add-style.component.cy.ts similarity index 100% rename from npm/angular/src/app/add-style/add-style.component.cy-spec.ts rename to npm/angular/src/app/add-style/add-style.component.cy.ts diff --git a/npm/angular/src/app/app.component.cy-spec.ts b/npm/angular/src/app/app.component.cy.ts similarity index 100% rename from npm/angular/src/app/app.component.cy-spec.ts rename to npm/angular/src/app/app.component.cy.ts diff --git a/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts b/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts deleted file mode 100644 index cfe6f9e672..0000000000 --- a/npm/angular/src/app/assets-image/assets-image.component.cy-spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { initEnv, mount } from '@cypress/angular' -import { AppModule } from '../app.module' -import { AssetsImageComponent } from './assets-image.component' - -describe('AssetsImageComponent', () => { - // FIXME: Find out why this fails and fix it. - it.skip('should create', () => { - initEnv(AssetsImageComponent) - mount(AssetsImageComponent) - // add "fileServerFolder": "src" in cypress.json - cy.get('img#noSlash') - .should('be.visible') - .and(($img) => { - const img = $img[0] as HTMLImageElement - - expect(img.naturalWidth).to.be.greaterThan(0) - }) - - cy.get('img#slash') - .should('be.visible') - .and(($img) => { - const img = $img[0] as HTMLImageElement - - expect(img.naturalWidth).to.be.greaterThan(0) - }) - }) - - // FIXME: Find out why this fails and fix it. - it.skip('should create with AppModule', () => { - initEnv({ imports: [AppModule] }) - mount(AssetsImageComponent) - // add "fileServerFolder": "src" in cypress.json - cy.get('img#noSlash') - .should('be.visible') - .and(($img) => { - const img = $img[0] as HTMLImageElement - - expect(img.naturalWidth).to.be.greaterThan(0) - }) - - cy.get('img#slash') - .should('be.visible') - .and(($img) => { - const img = $img[0] as HTMLImageElement - - expect(img.naturalWidth).to.be.greaterThan(0) - }) - }) -}) diff --git a/npm/angular/src/app/assets-image/assets-image.component.cy.ts b/npm/angular/src/app/assets-image/assets-image.component.cy.ts new file mode 100644 index 0000000000..9770b55586 --- /dev/null +++ b/npm/angular/src/app/assets-image/assets-image.component.cy.ts @@ -0,0 +1,49 @@ +import { initEnv, mount } from '@cypress/angular' +import { AppModule } from '../app.module' +import { AssetsImageComponent } from './assets-image.component' + +describe('AssetsImageComponent', () => { + // FIXME: Find out why this fails and fix it. + it.skip('should create', () => { + initEnv(AssetsImageComponent) + mount(AssetsImageComponent) + // add "fileServerFolder": "src" in cypress.config.{ts|js} + cy.get('img#noSlash') + .should('be.visible') + .and(($img) => { + const img = $img[0] as HTMLImageElement + + expect(img.naturalWidth).to.be.greaterThan(0) + }) + + cy.get('img#slash') + .should('be.visible') + .and(($img) => { + const img = $img[0] as HTMLImageElement + + expect(img.naturalWidth).to.be.greaterThan(0) + }) + }) + + // FIXME: Find out why this fails and fix it. + it.skip('should create with AppModule', () => { + initEnv({ imports: [AppModule] }) + mount(AssetsImageComponent) + // add "fileServerFolder": "src" in cypress.config.{ts|js} + cy.get('img#noSlash') + .should('be.visible') + .and(($img) => { + const img = $img[0] as HTMLImageElement + + expect(img.naturalWidth).to.be.greaterThan(0) + }) + + cy.get('img#slash') + .should('be.visible') + .and(($img) => { + const img = $img[0] as HTMLImageElement + + expect(img.naturalWidth).to.be.greaterThan(0) + }) + }) +}) diff --git a/npm/angular/src/app/bootstrap-button/bootstrap-button.component.cy-spec.ts b/npm/angular/src/app/bootstrap-button/bootstrap-button.component.cy.ts similarity index 100% rename from npm/angular/src/app/bootstrap-button/bootstrap-button.component.cy-spec.ts rename to npm/angular/src/app/bootstrap-button/bootstrap-button.component.cy.ts diff --git a/npm/angular/src/app/directives/highlight/highlight.directive.cy-spec.ts b/npm/angular/src/app/directives/highlight/highlight.directive.cy.ts similarity index 100% rename from npm/angular/src/app/directives/highlight/highlight.directive.cy-spec.ts rename to npm/angular/src/app/directives/highlight/highlight.directive.cy.ts diff --git a/npm/angular/src/app/html-mount/html-mount.component.cy-spec.ts b/npm/angular/src/app/html-mount/html-mount.component.cy.ts similarity index 100% rename from npm/angular/src/app/html-mount/html-mount.component.cy-spec.ts rename to npm/angular/src/app/html-mount/html-mount.component.cy.ts diff --git a/npm/angular/src/app/image-snapshot/image-snapshot.component.cy-spec.ts b/npm/angular/src/app/image-snapshot/image-snapshot.component.cy.ts similarity index 100% rename from npm/angular/src/app/image-snapshot/image-snapshot.component.cy-spec.ts rename to npm/angular/src/app/image-snapshot/image-snapshot.component.cy.ts diff --git a/npm/angular/src/app/input/input.component.cy-spec.ts b/npm/angular/src/app/input/input.component.cy.ts similarity index 100% rename from npm/angular/src/app/input/input.component.cy-spec.ts rename to npm/angular/src/app/input/input.component.cy.ts diff --git a/npm/angular/src/app/material-button/material-button.component.cy-spec.ts b/npm/angular/src/app/material-button/material-button.component.cy.ts similarity index 100% rename from npm/angular/src/app/material-button/material-button.component.cy-spec.ts rename to npm/angular/src/app/material-button/material-button.component.cy.ts diff --git a/npm/angular/src/app/my-values.service.cy-spec.ts b/npm/angular/src/app/my-values.service.cy.ts similarity index 100% rename from npm/angular/src/app/my-values.service.cy-spec.ts rename to npm/angular/src/app/my-values.service.cy.ts diff --git a/npm/angular/src/app/network/network.component.cy-spec.ts b/npm/angular/src/app/network/network.component.cy.ts similarity index 100% rename from npm/angular/src/app/network/network.component.cy-spec.ts rename to npm/angular/src/app/network/network.component.cy.ts diff --git a/npm/angular/src/app/ng-inline-svg/ng-inline-svg.component.cy-spec.ts b/npm/angular/src/app/ng-inline-svg/ng-inline-svg.component.cy.ts similarity index 100% rename from npm/angular/src/app/ng-inline-svg/ng-inline-svg.component.cy-spec.ts rename to npm/angular/src/app/ng-inline-svg/ng-inline-svg.component.cy.ts diff --git a/npm/angular/src/app/on-push-strat/on-push-strat.component.cy-spec.ts b/npm/angular/src/app/on-push-strat/on-push-strat.component.cy.ts similarity index 100% rename from npm/angular/src/app/on-push-strat/on-push-strat.component.cy-spec.ts rename to npm/angular/src/app/on-push-strat/on-push-strat.component.cy.ts diff --git a/npm/angular/src/app/output-subscribe/output-subscribe.component.cy-spec.ts b/npm/angular/src/app/output-subscribe/output-subscribe.component.cy.ts similarity index 100% rename from npm/angular/src/app/output-subscribe/output-subscribe.component.cy-spec.ts rename to npm/angular/src/app/output-subscribe/output-subscribe.component.cy.ts diff --git a/npm/angular/src/app/pipes/capitalize/capitalize.pipe.cy-spec.ts b/npm/angular/src/app/pipes/capitalize/capitalize.pipe.cy.ts similarity index 100% rename from npm/angular/src/app/pipes/capitalize/capitalize.pipe.cy-spec.ts rename to npm/angular/src/app/pipes/capitalize/capitalize.pipe.cy.ts diff --git a/npm/angular/src/app/primeng-button/primeng-button.component.cy-spec.ts b/npm/angular/src/app/primeng-button/primeng-button.component.cy.ts similarity index 100% rename from npm/angular/src/app/primeng-button/primeng-button.component.cy-spec.ts rename to npm/angular/src/app/primeng-button/primeng-button.component.cy.ts diff --git a/npm/angular/src/app/routing/routing.component.cy-spec.ts b/npm/angular/src/app/routing/routing.component.cy.ts similarity index 100% rename from npm/angular/src/app/routing/routing.component.cy-spec.ts rename to npm/angular/src/app/routing/routing.component.cy.ts diff --git a/npm/angular/src/app/scss-style/scss-style.component.cy-spec.ts b/npm/angular/src/app/scss-style/scss-style.component.cy.ts similarity index 100% rename from npm/angular/src/app/scss-style/scss-style.component.cy-spec.ts rename to npm/angular/src/app/scss-style/scss-style.component.cy.ts diff --git a/npm/angular/src/app/service-stub/service-stub.component.cy-spec.ts b/npm/angular/src/app/service-stub/service-stub.component.cy.ts similarity index 100% rename from npm/angular/src/app/service-stub/service-stub.component.cy-spec.ts rename to npm/angular/src/app/service-stub/service-stub.component.cy.ts diff --git a/npm/angular/src/app/timeout/timeout.component.cy-spec.ts b/npm/angular/src/app/timeout/timeout.component.cy.ts similarity index 100% rename from npm/angular/src/app/timeout/timeout.component.cy-spec.ts rename to npm/angular/src/app/timeout/timeout.component.cy.ts diff --git a/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts b/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts deleted file mode 100644 index de7528ea0b..0000000000 --- a/npm/angular/src/app/use-custom-element/use-custom-element.component.cy-spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' -import { initEnv, mount } from '@cypress/angular' -// You have to import your custom element -// And in cypress.json activate "includeShadowDom" configuration -import '../my-custom-element' -import { UseCustomElementComponent } from './use-custom-element.component' - -describe('AddStyleComponent', () => { - it('component with custom element shadow dom', () => { - initEnv(UseCustomElementComponent, { schemas: [CUSTOM_ELEMENTS_SCHEMA] }) - mount(UseCustomElementComponent) - cy.contains('use-custom-element works!') - cy.get('my-custom-element') - .shadow() - .get('button') - .should('have.text', 'Custom element button') - .should('have.css', 'color', 'rgb(255, 0, 0)') - }) -}) diff --git a/npm/angular/src/app/use-custom-element/use-custom-element.component.cy.ts b/npm/angular/src/app/use-custom-element/use-custom-element.component.cy.ts new file mode 100644 index 0000000000..1046008f32 --- /dev/null +++ b/npm/angular/src/app/use-custom-element/use-custom-element.component.cy.ts @@ -0,0 +1,19 @@ +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' +import { initEnv, mount } from '@cypress/angular' +// You have to import your custom element +// And in cypress.config.{ts|js} activate "includeShadowDom" configuration +import '../my-custom-element' +import { UseCustomElementComponent } from './use-custom-element.component' + +describe('AddStyleComponent', () => { + it('component with custom element shadow dom', () => { + initEnv(UseCustomElementComponent, { schemas: [CUSTOM_ELEMENTS_SCHEMA] }) + mount(UseCustomElementComponent) + cy.contains('use-custom-element works!') + cy.get('my-custom-element') + .shadow() + .get('button') + .should('have.text', 'Custom element button') + .should('have.css', 'color', 'rgb(255, 0, 0)') + }) +}) diff --git a/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js b/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js index 9947ff4275..f1ff8aa8b3 100644 --- a/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js +++ b/npm/create-cypress-tests/__snapshots__/init-component-testing.test.ts.js @@ -1,8 +1,8 @@ -exports['injects guessed next.js template cypress.json'] = ` -{ - "componentFolder": "src", - "testFiles": "**/*.spec.{js,ts,jsx,tsx}" -} +exports['injects guessed next.js template cypress.config.ts'] = ` +export default { + specPattern: "src/**/*.spec.{js,ts,jsx,tsx}" +}; + ` exports['injects guessed next.js template plugins/index.js'] = ` @@ -18,11 +18,11 @@ module.exports = (on, config) => { ` -exports['Injected overridden webpack template cypress.json'] = ` -{ - "componentFolder": "cypress/component", - "testFiles": "**/*.spec.{js,ts,jsx,tsx}" -} +exports['Injected overridden webpack template cypress.config.ts'] = ` +export default { + specPattern: "cypress/component/**/*.spec.{js,ts,jsx,tsx}" +}; + ` exports['Injected overridden webpack template plugins/index.js'] = ` @@ -38,6 +38,6 @@ module.exports = (on, config) => { ` -exports['Injected overridden webpack template support/index.js'] = ` +exports['Injected overridden webpack template support/component.js'] = ` import "./commands.js"; ` diff --git a/npm/create-cypress-tests/cypress.config.js b/npm/create-cypress-tests/cypress.config.js new file mode 100644 index 0000000000..4ba52ba2c8 --- /dev/null +++ b/npm/create-cypress-tests/cypress.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/npm/create-cypress-tests/package.json b/npm/create-cypress-tests/package.json index dda6627a31..f6dbf6fdb9 100644 --- a/npm/create-cypress-tests/package.json +++ b/npm/create-cypress-tests/package.json @@ -3,7 +3,7 @@ "version": "0.0.0-development", "description": "Cypress smart installation wizard", "private": false, - "main": "index.js", + "main": "dist/src/main.js", "scripts": { "build": "yarn prepare-example && tsc -p ./tsconfig.json && node scripts/example copy-to ./dist/initial-template && yarn prepare-copy-templates", "build-prod": "yarn build", @@ -26,7 +26,8 @@ "fs-extra": "^9.1.0", "glob": "^7.1.6", "inquirer": "7.3.3", - "ora": "^5.1.0" + "ora": "^5.1.0", + "recast": "0.20.4" }, "devDependencies": { "@types/babel__core": "^7.1.2", @@ -41,6 +42,10 @@ "snap-shot-it": "7.9.3", "typescript": "^4.2.3" }, + "files": [ + "dist", + "bin" + ], "bin": { "create-cypress-tests": "dist/src/index.js" }, diff --git a/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts b/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts index 22e5858dca..b7089d3cc1 100644 --- a/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts +++ b/npm/create-cypress-tests/src/component-testing/babel/babelTransform.ts @@ -2,6 +2,7 @@ import path from 'path' import * as fs from 'fs-extra' import * as babel from '@babel/core' import * as babelTypes from '@babel/types' +import { prettifyCode } from '../../utils' type AST = ReturnType @@ -11,13 +12,6 @@ export type PluginsConfigAst = { requiresReturnConfig?: true } -function tryRequirePrettier () { - try { - return require('prettier') - } catch (e) { - return null - } -} const sharedBabelOptions = { // disable user config configFile: false, @@ -47,11 +41,7 @@ async function transformFileViaPlugin (filePath: string, babelPlugin: babel.Plug return false } - const maybePrettier = tryRequirePrettier() - - if (maybePrettier && maybePrettier.format) { - finalCode = maybePrettier.format(finalCode, { parser: 'babel' }) - } + finalCode = await prettifyCode(finalCode) await fs.writeFile(filePath, finalCode) diff --git a/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts new file mode 100644 index 0000000000..8c9e3381e9 --- /dev/null +++ b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.test.ts @@ -0,0 +1,409 @@ +/// + +import * as path from 'path' +import { expect } from 'chai' + +import * as fs from 'fs-extra' +import { insertValueInJSString, insertValuesInConfigFile } from './configFileUpdater' +const projectRoot = process.cwd() + +// Test util - if needed outside the tests we can move it to utils +const stripIndent = (strings: any, ...args: any) => { + const parts = [] + + for (let i = 0; i < strings.length; i++) { + parts.push(strings[i]) + + if (i < strings.length - 1) { + parts.push(`<<${i}>>`) + } + } + + const lines = parts.join('').split('\n') + const firstLine = lines[0].length === 0 ? lines[1] : lines[0] + let indentSize = 0 + + for (let i = 0; i < firstLine.length; i++) { + if (firstLine[i] === ' ') { + indentSize++ + continue + } + + break + } + + const strippedLines = lines.map((line) => line.substring(indentSize)) + + let result = strippedLines.join('\n').trimLeft() + + args.forEach((arg: any, i: any) => { + result = result.replace(`<<${i}>>`, `${arg}`) + }) + + return result +} + +describe('lib/util/config-file-updater', () => { + context('with js files', () => { + describe('#insertValueInJSString', () => { + describe('es6 vs es5', () => { + it('finds the object litteral and adds the values to it es6', async () => { + const src = stripIndent`\ + export default { + foo: 42, + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + viewportWidth: 400, + foo: 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('finds the object litteral and adds the values to it es5', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42, + } + ` + + const expectedOutput = stripIndent`\ + module.exports = { + projectId: "id1234", + viewportWidth: 400, + foo: 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('works with and without the quotes around keys', async () => { + const src = stripIndent`\ + export default { + "foo": 42, + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + viewportWidth: 400, + "foo": 42, + } + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('defineConfig', () => { + it('skips defineConfig and add to the object inside', async () => { + const src = stripIndent`\ + import { defineConfig } from "cypress" + export default defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + import { defineConfig } from "cypress" + export default defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('skips defineConfig even if it renamed in an import (es6)', async () => { + const src = stripIndent`\ + import { defineConfig as cy_defineConfig } from "cypress" + export default cy_defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + import { defineConfig as cy_defineConfig } from "cypress" + export default cy_defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + + it('skips defineConfig even if it renamed in a require (es5)', async () => { + const src = stripIndent`\ + const { defineConfig: cy_defineConfig } = require("cypress") + module.exports = cy_defineConfig({ + foo: 42, + }) + ` + + const expectedOutput = stripIndent`\ + const { defineConfig: cy_defineConfig } = require("cypress") + module.exports = cy_defineConfig({ + projectId: "id1234", + viewportWidth: 400, + foo: 42, + }) + ` + + const output = await insertValueInJSString(src, { projectId: 'id1234', viewportWidth: 400 }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('updates', () => { + it('updates a value if the same value is found in resolved config', async () => { + const src = stripIndent`\ + export default { + foo: 42, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('accepts inline comments', async () => { + const src = stripIndent`\ + export default { + foo: 12, // will do this later + viewportWidth: 800, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, // will do this later + viewportWidth: 800, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('updates a value even when this value is explicitely undefined', async () => { + const src = stripIndent`\ + export default { + foo: undefined, // will do this later + viewportWidth: 800, + } + ` + const expectedOutput = stripIndent`\ + export default { + foo: 1000, // will do this later + viewportWidth: 800, + } + ` + + const output = await insertValueInJSString(src, { foo: 1000 }) + + expect(output).to.equal(expectedOutput) + }) + + it('updates values and inserts config', async () => { + const src = stripIndent`\ + export default { + foo: 42, + bar: 84, + component: { + devServer() { + return null + } + } + } + ` + + const expectedOutput = stripIndent`\ + export default { + projectId: "id1234", + foo: 1000, + bar: 3000, + component: { + devServer() { + return null + } + } + } + ` + + const output = await insertValueInJSString(src, { foo: 1000, bar: 3000, projectId: 'id1234' }) + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('subkeys', () => { + it('inserts nested values', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42 + } + ` + + const output = await insertValueInJSString(src, { component: { specPattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + component: { + specPattern: "src/**/*.spec.cy.js", + }, + foo: 42 + } + ` + + expect(output).to.equal(expectedOutput) + }) + + it('inserts nested values into existing keys', async () => { + const src = stripIndent`\ + module.exports = { + component: { + viewportWidth: 800 + }, + foo: 42 + } + ` + + const output = await insertValueInJSString(src, { component: { specPattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + component: { + specPattern: "src/**/*.spec.cy.js", + viewportWidth: 800 + }, + foo: 42 + } + ` + + expect(output).to.equal(expectedOutput) + }) + + it('updates nested values', async () => { + const src = stripIndent`\ + module.exports = { + foo: 42, + component: { + specPattern: 'components/**/*.spec.cy.js', + foo: 82 + } + }` + + const output = await insertValueInJSString(src, { component: { specPattern: 'src/**/*.spec.cy.js' } }) + + const expectedOutput = stripIndent`\ + module.exports = { + foo: 42, + component: { + specPattern: "src/**/*.spec.cy.js", + foo: 82 + } + }` + + expect(output).to.equal(expectedOutput) + }) + }) + + describe('failures', () => { + it('fails if not an object litteral', () => { + const src = [ + 'const foo = {}', + 'export default foo', + ].join('\n') + + return insertValueInJSString(src, { bar: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails if one of the values to update is not a literal', () => { + const src = [ + 'const bar = 12', + 'export default {', + ' foo: bar', + '}', + ].join('\n') + + return insertValueInJSString(src, { foo: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails with inlined values', () => { + const src = stripIndent`\ + const foo = 12 + export default { + foo + } + ` + + return insertValueInJSString(src, { foo: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + + it('fails if there is a spread', () => { + const src = stripIndent`\ + const foo = { bar: 12 } + export default { + bar: 8, + ...foo + } + ` + + return insertValueInJSString(src, { bar: 10 }) + .then(() => { + throw Error('this should not succeed') + }) + .catch((err) => { + expect(err.message).to.equal('Cypress was unable to add/update values in your configuration file.') + }) + }) + }) + }) + }) +}) diff --git a/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts new file mode 100644 index 0000000000..6d16505c40 --- /dev/null +++ b/npm/create-cypress-tests/src/component-testing/config-file-updater/configFileUpdater.ts @@ -0,0 +1,295 @@ +import _ from 'lodash' +import { parse } from '@babel/parser' +import type { File } from '@babel/types' +import type { NodePath } from 'ast-types/lib/node-path' +import { visit } from 'recast' +import type { namedTypes } from 'ast-types' +import * as fs from 'fs-extra' +import { prettifyCode } from '../../utils' + +export async function insertValuesInConfigFile (filePath: string, obj: Record = {}) { + await insertValuesInJavaScript(filePath, obj) + + return true +} + +export async function insertValuesInJavaScript (filePath: string, obj: Record) { + const fileContents = await fs.readFile(filePath, { encoding: 'utf8' }) + + let finalCode = await insertValueInJSString(fileContents, obj) + + const prettifiedCode = await prettifyCode(finalCode) + + if (prettifiedCode) { + finalCode = prettifiedCode + } + + await fs.writeFile(filePath, finalCode) +} + +export async function insertValueInJSString (fileContents: string, obj: Record): Promise { + const ast = parse(fileContents, { plugins: ['typescript'], sourceType: 'module' }) + + let objectLiteralNode: namedTypes.ObjectExpression | undefined + + function handleExport (nodePath: NodePath | NodePath): void { + if (nodePath.node.type === 'CallExpression' + && nodePath.node.callee.type === 'Identifier') { + const functionName = nodePath.node.callee.name + + if (isDefineConfigFunction(ast, functionName)) { + return handleExport(nodePath.get('arguments', 0)) + } + } + + if (nodePath.node.type === 'ObjectExpression' && !nodePath.node.properties.find((prop) => prop.type !== 'ObjectProperty')) { + objectLiteralNode = nodePath.node + + return + } + + throw new Error('Cypress was unable to add/update values in your configuration file.') + } + + visit(ast, { + visitAssignmentExpression (nodePath) { + if (nodePath.node.left.type === 'MemberExpression') { + if (nodePath.node.left.object.type === 'Identifier' && nodePath.node.left.object.name === 'module' + && nodePath.node.left.property.type === 'Identifier' && nodePath.node.left.property.name === 'exports') { + handleExport(nodePath.get('right')) + } + } + + return false + }, + visitExportDefaultDeclaration (nodePath) { + handleExport(nodePath.get('declaration')) + + return false + }, + }) + + const splicers: Splicer[] = [] + + if (!objectLiteralNode) { + // if the export is no object litteral + throw new Error('Cypress was unable to add/update values in your configuration file.') + } + + setRootKeysSplicers(splicers, obj, objectLiteralNode!, ' ') + setSubKeysSplicers(splicers, obj, objectLiteralNode!, ' ', ' ') + + // sort splicers to keep the order of the original file + const sortedSplicers = splicers.sort((a, b) => a.start === b.start ? 0 : a.start > b.start ? 1 : -1) + + if (!sortedSplicers.length) return fileContents + + let nextStartingIndex = 0 + let resultCode = '' + + sortedSplicers.forEach((splicer) => { + resultCode += fileContents.slice(nextStartingIndex, splicer.start) + splicer.replaceString + nextStartingIndex = splicer.end + }) + + return resultCode + fileContents.slice(nextStartingIndex) +} + +export function isDefineConfigFunction (ast: File, functionName: string): boolean { + let value = false + + visit(ast, { + visitVariableDeclarator (nodePath) { + // if this is a require of cypress + if (nodePath.node.init?.type === 'CallExpression' + && nodePath.node.init.callee.type === 'Identifier' + && nodePath.node.init.callee.name === 'require' + && nodePath.node.init.arguments[0].type === 'StringLiteral' + && nodePath.node.init.arguments[0].value === 'cypress') { + if (nodePath.node.id?.type === 'ObjectPattern') { + const defineConfigFunctionNode = nodePath.node.id.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === 'defineConfig' + }) + + if (defineConfigFunctionNode) { + value = (defineConfigFunctionNode as any).value?.name === functionName + } + } + } + + return false + }, + visitImportDeclaration (nodePath) { + if (nodePath.node.source.type === 'StringLiteral' + && nodePath.node.source.value === 'cypress') { + const defineConfigFunctionNode = nodePath.node.specifiers?.find((specifier) => { + return specifier.type === 'ImportSpecifier' + && specifier.imported.type === 'Identifier' + && specifier.imported.name === 'defineConfig' + }) + + if (defineConfigFunctionNode) { + value = (defineConfigFunctionNode as any).local?.name === functionName + } + } + + return false + }, + }) + + return value +} + +function setRootKeysSplicers ( + splicers: Splicer[], + obj: Record, + objectLiteralNode: namedTypes.ObjectExpression, + lineStartSpacer: string, +) { + const objectLiteralStartIndex = (objectLiteralNode as any).start + 1 + // add values + const objKeys = Object.keys(obj).filter((key) => ['boolean', 'number', 'string'].includes(typeof obj[key])) + + // update values + const keysToUpdate = objKeys.filter((key) => { + return objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === key + }) + }) + + keysToUpdate.forEach( + (key) => { + const propertyToUpdate = propertyFromKey(objectLiteralNode, key) + + if (propertyToUpdate) { + setSplicerToUpdateProperty(splicers, propertyToUpdate, obj[key], key, obj) + } + }, + ) + + const keysToInsert = objKeys.filter((key) => !keysToUpdate.includes(key)) + + if (keysToInsert.length) { + const valuesInserted = `\n${lineStartSpacer}${ keysToInsert.map((key) => `${key}: ${JSON.stringify(obj[key])},`).join(`\n${lineStartSpacer}`)}` + + splicers.push({ + start: objectLiteralStartIndex, + end: objectLiteralStartIndex, + replaceString: valuesInserted, + }) + } +} + +function setSubKeysSplicers ( + splicers: Splicer[], + obj: Record, + objectLiteralNode: namedTypes.ObjectExpression, + lineStartSpacer: string, + parentLineStartSpacer: string, +) { + const objectLiteralStartIndex = (objectLiteralNode as any).start + 1 + + const keysToUpdateWithObjects: string[] = [] + + const objSubkeys = Object.keys(obj).filter((key) => typeof obj[key] === 'object').reduce((acc: Array<{parent: string, subkey: string}>, key) => { + keysToUpdateWithObjects.push(key) + Object.entries(obj[key]).forEach(([subkey, value]) => { + if (['boolean', 'number', 'string'].includes(typeof value)) { + acc.push({ parent: key, subkey }) + } + }) + + return acc + }, []) + + // add values where the parent key needs to be created + const subkeysToInsertWithoutKey = objSubkeys.filter(({ parent }) => { + return !objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === parent + }) + }) + const keysToInsertForSubKeys: Record = {} + + subkeysToInsertWithoutKey.forEach((keyTuple) => { + const subkeyList = keysToInsertForSubKeys[keyTuple.parent] || [] + + subkeyList.push(keyTuple.subkey) + keysToInsertForSubKeys[keyTuple.parent] = subkeyList + }) + + let subvaluesInserted = '' + + for (const key in keysToInsertForSubKeys) { + subvaluesInserted += `\n${parentLineStartSpacer}${key}: {` + keysToInsertForSubKeys[key].forEach((subkey) => { + subvaluesInserted += `\n${parentLineStartSpacer}${lineStartSpacer}${subkey}: ${JSON.stringify(obj[key][subkey])},` + }) + + subvaluesInserted += `\n${parentLineStartSpacer}},` + } + + if (subkeysToInsertWithoutKey.length) { + splicers.push({ + start: objectLiteralStartIndex, + end: objectLiteralStartIndex, + replaceString: subvaluesInserted, + }) + } + + // add/update values where parent key already exists + keysToUpdateWithObjects.filter((parent) => { + return objectLiteralNode.properties.find((prop) => { + return prop.type === 'ObjectProperty' + && prop.key.type === 'Identifier' + && prop.key.name === parent + }) + }).forEach((key) => { + const propertyToUpdate = propertyFromKey(objectLiteralNode, key) + + if (propertyToUpdate?.value.type === 'ObjectExpression') { + setRootKeysSplicers(splicers, obj[key], propertyToUpdate.value, parentLineStartSpacer + lineStartSpacer) + } + }) +} + +function setSplicerToUpdateProperty (splicers: Splicer[], + propertyToUpdate: namedTypes.ObjectProperty, + updatedValue: any, + key: string, + obj: Record) { + if (propertyToUpdate && (isPrimitive(propertyToUpdate.value) || isUndefinedOrNull(propertyToUpdate.value))) { + splicers.push({ + start: (propertyToUpdate.value as any).start, + end: (propertyToUpdate.value as any).end, + replaceString: JSON.stringify(updatedValue), + }) + } else { + throw new Error('Cypress was unable to add/update values in your configuration file.') + } +} + +function propertyFromKey (objectLiteralNode: namedTypes.ObjectExpression | undefined, key: string): namedTypes.ObjectProperty | undefined { + return objectLiteralNode?.properties.find((prop) => { + return prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && prop.key.name === key + }) as namedTypes.ObjectProperty +} + +function isPrimitive (value: NodePath['node']): value is namedTypes.NumericLiteral | namedTypes.StringLiteral | namedTypes.BooleanLiteral { + return value.type === 'NumericLiteral' || value.type === 'StringLiteral' || value.type === 'BooleanLiteral' +} + +function isUndefinedOrNull (value: NodePath['node']): value is namedTypes.Identifier { + return value.type === 'Identifier' && ['undefined', 'null'].includes(value.name) +} + +interface Splicer{ + start: number + end: number + replaceString: string +} diff --git a/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts b/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts index e070b836ff..2db6b20baf 100644 --- a/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts +++ b/npm/create-cypress-tests/src/component-testing/init-component-testing.test.ts @@ -20,7 +20,7 @@ describe('init component tests script', () => { let execStub: SinonStub | null = null const e2eTestOutputPath = path.resolve(__dirname, '..', 'test-output') - const cypressConfigPath = path.join(e2eTestOutputPath, 'cypress.json') + const cypressConfigPath = path.join(e2eTestOutputPath, 'cypress.config.ts') beforeEach(async () => { logSpy = sinon.spy(global.console, 'log') @@ -55,9 +55,9 @@ describe('init component tests script', () => { function snapshotGeneratedFiles (name: string) { snapshot( - `${name} cypress.json`, + `${name} cypress.config.ts`, fs.readFileSync( - path.join(e2eTestOutputPath, 'cypress.json'), + path.join(e2eTestOutputPath, 'cypress.config.ts'), { encoding: 'utf-8' }, ), ) @@ -71,7 +71,7 @@ describe('init component tests script', () => { ) const supportFile = fs.readFileSync( - path.join(e2eTestOutputPath, 'cypress', 'support', 'index.js'), + path.join(e2eTestOutputPath, 'cypress', 'support', 'component.js'), { encoding: 'utf-8' }, ) @@ -81,9 +81,9 @@ describe('init component tests script', () => { } snapshot( - `${name} support/index.js`, + `${name} support/component.js`, fs.readFileSync( - path.join(e2eTestOutputPath, 'cypress', 'support', 'index.js'), + path.join(e2eTestOutputPath, 'cypress', 'support', 'component.js'), { encoding: 'utf-8' }, ), ) @@ -91,8 +91,8 @@ describe('init component tests script', () => { it('determines more presumable configuration to suggest', async () => { createTempFiles({ - '/cypress.json': '{}', - '/cypress/support/index.js': '', + '/cypress.config.ts': 'export default {}', + '/cypress/support/component.js': '', '/cypress/plugins/index.js': 'module.exports = (on, config) => {}', // For next.js user will have babel config, but we want to suggest to use the closest config for the application code '/babel.config.js': 'module.exports = { }', @@ -114,8 +114,8 @@ describe('init component tests script', () => { it('automatically suggests to the user which config to use', async () => { createTempFiles({ - '/cypress.json': '{}', - '/cypress/support/index.js': 'import "./commands.js";', + '/cypress.config.ts': 'export default {}', + '/cypress/support/component.js': 'import "./commands.js";', '/cypress/plugins/index.js': 'module.exports = () => {}', '/package.json': JSON.stringify({ dependencies: { @@ -145,7 +145,7 @@ describe('init component tests script', () => { it('Asks for preferred bundling tool if can not determine the right one', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { } }), }) @@ -170,7 +170,7 @@ describe('init component tests script', () => { it('Asks for framework if more than 1 option was auto detected', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { react: '*', vue: '^2.4.5' } }), }) @@ -195,7 +195,7 @@ describe('init component tests script', () => { it('installs the right adapter', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/webpack.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { react: '16.4.5' } }), }) @@ -213,7 +213,7 @@ describe('init component tests script', () => { it('installs the right adapter for vue 3', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/vite.config.js': 'module.exports = { }', '/package.json': JSON.stringify({ dependencies: { vue: '^3.0.0' } }), }) @@ -226,7 +226,7 @@ describe('init component tests script', () => { }) as any) await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true }) - expect(execStub).to.be.calledWith('yarn add @cypress/vue@3 --dev') + expect(execStub).to.be.calledWith('yarn add @cypress/vue --dev') }) it('suggest the right instruction based on user template choice', async () => { @@ -236,7 +236,7 @@ describe('init component tests script', () => { react: '^16.0.0', }, }), - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', }) promptSpy = sinon.stub(inquirer, 'prompt').returns(Promise.resolve({ @@ -253,9 +253,9 @@ describe('init component tests script', () => { ).to.be.true }) - it('suggests right docs example and cypress.json config based on the `componentFolder` answer', async () => { + it('suggests right docs example and cypress.config.ts config based on the `componentFolder` answer', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/package.json': JSON.stringify({ dependencies: { react: '^16.0.0', @@ -270,12 +270,11 @@ describe('init component tests script', () => { await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true }) - const injectedCode = fs.readFileSync(path.join(e2eTestOutputPath, 'cypress.json'), { encoding: 'utf-8' }) + const injectedCode = require(path.join(e2eTestOutputPath, 'cypress.config.ts')) - expect(injectedCode).to.equal(JSON.stringify( + expect(JSON.stringify(injectedCode.default, null, 2)).to.equal(JSON.stringify( { - componentFolder: 'cypress/component', - testFiles: '**/*.spec.{js,ts,jsx,tsx}', + specPattern: 'cypress/component/**/*.spec.{js,ts,jsx,tsx}', }, null, 2, @@ -284,7 +283,7 @@ describe('init component tests script', () => { it('Shows help message if cypress files are not created', async () => { createTempFiles({ - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', '/package.json': JSON.stringify({ dependencies: { react: '^16.0.0', @@ -307,10 +306,10 @@ describe('init component tests script', () => { ).to.be.true }) - it('Doesn\'t affect injected code if user has custom babel.config.js', async () => { + it(`Doesn't affect injected code if user has custom babel.config.js`, async () => { createTempFiles({ '/cypress/plugins/index.js': 'module.exports = (on, config) => {}', - '/cypress.json': '{}', + '/cypress.config.ts': 'export default {}', 'babel.config.js': `module.exports = ${JSON.stringify({ presets: [ '@babel/preset-env', diff --git a/npm/create-cypress-tests/src/component-testing/init-component-testing.ts b/npm/create-cypress-tests/src/component-testing/init-component-testing.ts index 7267470487..a79908088f 100644 --- a/npm/create-cypress-tests/src/component-testing/init-component-testing.ts +++ b/npm/create-cypress-tests/src/component-testing/init-component-testing.ts @@ -8,6 +8,7 @@ import { guessTemplate } from './templates/guessTemplate' import { installFrameworkAdapter } from './installFrameworkAdapter' import { injectPluginsCode, getPluginsSourceExample } from './babel/babelTransform' import { installDependency } from '../utils' +import { insertValuesInConfigFile } from './config-file-updater/configFileUpdater' async function injectOrShowConfigCode (injectFn: () => Promise, { code, @@ -51,27 +52,15 @@ async function injectOrShowConfigCode (injectFn: () => Promise, { injected ? printSuccess() : printFailure() } -async function injectAndShowCypressJsonConfig ( +async function injectAndShowCypressConfig ( cypressJsonPath: string, componentFolder: string, ) { const configToInject = { - componentFolder, - testFiles: '**/*.spec.{js,ts,jsx,tsx}', + specPattern: `${componentFolder}/**/*.spec.{js,ts,jsx,tsx}`, } - async function autoInjectCypressJson () { - const currentConfig = JSON.parse(await fs.readFile(cypressJsonPath, { encoding: 'utf-8' })) - - await fs.writeFile(cypressJsonPath, JSON.stringify({ - ...currentConfig, - ...configToInject, - }, null, 2)) - - return true - } - - await injectOrShowConfigCode(autoInjectCypressJson, { + await injectOrShowConfigCode(() => insertValuesInConfigFile(cypressJsonPath, configToInject), { code: JSON.stringify(configToInject, null, 2), language: 'js', filePath: cypressJsonPath, @@ -94,7 +83,7 @@ async function injectAndShowPluginConfig (template: Template, { code: await getPluginsSourceExample(ast), language: 'js', filePath: pluginsFilePath, - fallbackFileMessage: 'plugins file (https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Plugin-files)', + fallbackFileMessage: 'plugins file (https://on.cypress.io/plugins-file)', }) } @@ -171,7 +160,7 @@ export async function initComponentTesting ({ config, useYarn, cypressConfigP console.log(`Let's setup everything for component testing with ${chalk.cyan(chosenTemplateName)}:`) console.log() - await injectAndShowCypressJsonConfig(cypressConfigPath, componentFolder) + await injectAndShowCypressConfig(cypressConfigPath, componentFolder) await injectAndShowPluginConfig(chosenTemplate, { templatePayload, pluginsFilePath, diff --git a/npm/create-cypress-tests/src/component-testing/installFrameworkAdapter.ts b/npm/create-cypress-tests/src/component-testing/installFrameworkAdapter.ts index f037726731..18e669a02e 100644 --- a/npm/create-cypress-tests/src/component-testing/installFrameworkAdapter.ts +++ b/npm/create-cypress-tests/src/component-testing/installFrameworkAdapter.ts @@ -48,10 +48,16 @@ type InstallAdapterOptions = { useYarn: boolean } +const frameworkDependencies = { + react: '@cypress/react', + 'vue@2': '@cypress/vue2', + 'vue@3': '@cypress/vue', +} + export async function installFrameworkAdapter (cwd: string, options: InstallAdapterOptions) { const framework = await guessOrAskForFramework(cwd) - await installDependency(`@cypress/${framework}`, options) + await installDependency(frameworkDependencies[framework], options) return framework } diff --git a/npm/create-cypress-tests/src/findPackageJson.ts b/npm/create-cypress-tests/src/findPackageJson.ts index 090fe31c89..81858d319c 100644 --- a/npm/create-cypress-tests/src/findPackageJson.ts +++ b/npm/create-cypress-tests/src/findPackageJson.ts @@ -104,7 +104,7 @@ export function scanFSForAvailableDependency (cwd: string, lookingForDeps: Recor .some(([dependency, version]) => { return ( Boolean(lookingForDeps[dependency]) - && validateSemverVersion(version, lookingForDeps[dependency], dependency) + && validateSemverVersion(version, lookingForDeps[dependency] as string, dependency) ) }), } diff --git a/npm/create-cypress-tests/src/installCypress.ts b/npm/create-cypress-tests/src/installCypress.ts index ffb2727b1c..9abd21345b 100644 --- a/npm/create-cypress-tests/src/installCypress.ts +++ b/npm/create-cypress-tests/src/installCypress.ts @@ -15,7 +15,7 @@ type InstallCypressOpts = { async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) { let fileSpinner = ora('Creating config files').start() - await fs.outputFile(path.resolve(process.cwd(), 'cypress.json'), '{}\n') + await fs.outputFile(path.resolve(process.cwd(), useTypescript ? 'cypress.config.ts' : 'cypress.config.js'), useTypescript ? `export default {}` : `module.exports = {}\n`) await fs.copy( initialTemplate.getInitialPluginsFilePath(), path.resolve('cypress', 'plugins/index.js'), @@ -44,9 +44,10 @@ async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) '', ].join('\n') - const specFileToCreate = path.resolve('cypress', 'integration', useTypescript ? 'spec.ts' : 'spec.js') + const specFileName = useTypescript ? 'spec.cy.ts' : 'spec.cy.js' + const specFileToCreate = path.resolve('cypress', 'e2e', specFileName) - await fs.outputFile(path.resolve('cypress', 'integration', useTypescript ? 'spec.js' : 'spec.ts'), dummySpec) + await fs.outputFile(specFileToCreate, dummySpec) console.log(`In order to ignore examples a spec file ${chalk.green(path.relative(process.cwd(), specFileToCreate))}.`) } @@ -54,23 +55,24 @@ async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) } export async function findInstalledOrInstallCypress (options: InstallCypressOpts) { - let cypressJsonPath = await findUp('cypress.json') + const configFile = options.useTypescript ? 'cypress.config.ts' : 'cypress.config.js' + let cypressConfigPath = await findUp(configFile) - if (!cypressJsonPath) { + if (!cypressConfigPath) { await installDependency('cypress', options) await copyFiles(options) - cypressJsonPath = await findUp('cypress.json') + cypressConfigPath = await findUp(configFile) } - if (!cypressJsonPath) { + if (!cypressConfigPath) { throw new Error('Unexpected error during cypress installation.') } + const config = await import(cypressConfigPath) + return { - cypressConfigPath: cypressJsonPath, - config: JSON.parse( - fs.readFileSync(cypressJsonPath, { encoding: 'utf-8' }).toString(), - ) as Record, + cypressConfigPath, + config: config.default, } } diff --git a/npm/create-cypress-tests/src/main.test.ts b/npm/create-cypress-tests/src/main.test.ts index 0381b5ff55..93cdaa91a4 100644 --- a/npm/create-cypress-tests/src/main.test.ts +++ b/npm/create-cypress-tests/src/main.test.ts @@ -148,9 +148,9 @@ describe('create-cypress-tests', () => { await main({ useNpm: true, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false }) expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'plugins', 'index.js'))).to.equal(true) - expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'index.js'))).to.equal(true) + expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'e2e.js'))).to.equal(true) expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'commands.js'))).to.equal(true) - expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress.json'))).to.equal(true) + expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress.config.ts'))).to.equal(true) }) it('Copies tsconfig if typescript is installed', async () => { diff --git a/npm/create-cypress-tests/src/main.ts b/npm/create-cypress-tests/src/main.ts index f7901cd71c..818a58b943 100644 --- a/npm/create-cypress-tests/src/main.ts +++ b/npm/create-cypress-tests/src/main.ts @@ -64,8 +64,8 @@ function printCypressCommandsHelper (options: { shouldSetupComponentTesting: boo printCommand('cypress run', 'Runs tests in headless mode.') if (options.shouldSetupComponentTesting) { - printCommand('cypress open-ct', 'Opens cypress component-testing web app.') - printCommand('cypress run-ct', 'Runs component testing in headless mode.') + printCommand('cypress open --component', 'Opens Cypress component testing interactive mode.') + printCommand('cypress run-ct', 'Runs all Cypress component testing suites.') } } @@ -102,3 +102,5 @@ export async function main ({ useNpm, ignoreTs, setupComponentTesting, ignoreExa console.log(`\nHappy testing with ${chalk.green('cypress.io')} ๐ŸŒฒ\n`) } + +export { scanFSForAvailableDependency } diff --git a/npm/create-cypress-tests/src/utils.ts b/npm/create-cypress-tests/src/utils.ts index c42a92855e..e79055e602 100644 --- a/npm/create-cypress-tests/src/utils.ts +++ b/npm/create-cypress-tests/src/utils.ts @@ -60,3 +60,17 @@ export async function installDependency (name: string, options: { useYarn: boole cliSpinner.succeed() } + +export async function prettifyCode (finalCode?: string | null) { + try { + const maybePrettier = require('prettier') + + if (maybePrettier && maybePrettier.format) { + finalCode = maybePrettier.format(finalCode, { parser: 'babel' }) + } + } catch (e) { + return null + } finally { + return finalCode + } +} diff --git a/npm/cypress-schematic/README.md b/npm/cypress-schematic/README.md index a331d5e88f..c13d50a970 100644 --- a/npm/cypress-schematic/README.md +++ b/npm/cypress-schematic/README.md @@ -84,7 +84,7 @@ Read our docs to learn more about [launching browsers](https://on.cypress.io/lau ### Recording test results to the Cypress Dashboard -We recommend setting your [Cypress Dashboard](https://docs.cypress.io/guides/dashboard/introduction) recording key as an environment variable and NOT as a builder option when running it in CI. +We recommend setting your [Cypress Dashboard](https://on.cypress.io/features-dashboard) recording key as an environment variable and NOT as a builder option when running it in CI. ```json "cypress-run": { @@ -102,7 +102,7 @@ We recommend setting your [Cypress Dashboard](https://docs.cypress.io/guides/das } ``` -Read our docs to learn more about [recording test results](https://on.cypress.io/recording-project-runs) to the [Cypress Dashboard](https://docs.cypress.io/guides/dashboard/introduction). +Read our docs to learn more about [recording test results](https://on.cypress.io/recording-project-runs) to the [Cypress Dashboard](https://on.cypress.io/features-dashboard). ### Specifying a custom `cypress.json` config file @@ -181,8 +181,7 @@ In order to bypass the prompt asking for your e2e spec name, simply add a `--nam ng generate @cypress/schematic:e2e --name=login ``` -This will create a new spec file named `login.spec.ts` in the default Cypress folder location. - +This will create a new spec file named `login.cy.ts` in the default Cypress folder location. ### Specify Project diff --git a/npm/cypress-schematic/package.json b/npm/cypress-schematic/package.json index 75068019a7..de5a50461c 100644 --- a/npm/cypress-schematic/package.json +++ b/npm/cypress-schematic/package.json @@ -58,4 +58,4 @@ "save": "devDependencies" }, "schematics": "./src/schematics/collection.json" -} \ No newline at end of file +} diff --git a/npm/cypress-schematic/sandbox/package.json b/npm/cypress-schematic/sandbox/package.json index 97dd845d8b..6d4647bd81 100644 --- a/npm/cypress-schematic/sandbox/package.json +++ b/npm/cypress-schematic/sandbox/package.json @@ -10,22 +10,22 @@ "test": "ng test" }, "dependencies": { - "@angular/animations": "~12.0.0", - "@angular/common": "~12.0.0", - "@angular/compiler": "~12.0.0", - "@angular/core": "~12.0.0", - "@angular/forms": "~12.0.0", - "@angular/platform-browser": "~12.0.0", - "@angular/platform-browser-dynamic": "~12.0.0", - "@angular/router": "~12.0.0", + "@angular/animations": "~13.1.3", + "@angular/common": "~13.1.3", + "@angular/compiler": "~13.1.3", + "@angular/core": "~13.1.3", + "@angular/forms": "~13.1.3", + "@angular/platform-browser": "~13.1.3", + "@angular/platform-browser-dynamic": "~13.1.3", + "@angular/router": "~13.1.3", "rxjs": "~6.6.0", "tslib": "^2.1.0", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "~12.0.0", - "@angular/cli": "~12.0.0", - "@angular/compiler-cli": "~12.0.0", + "@angular-devkit/build-angular": "~13.1.4", + "@angular/cli": "~13.1.4", + "@angular/compiler-cli": "~13.1.3", "@types/jasmine": "~3.6.0", "@types/node": "^12.11.1", "jasmine-core": "~3.7.0", @@ -34,6 +34,6 @@ "karma-coverage": "~2.0.3", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", - "typescript": "~4.2.3" + "typescript": "~4.5.5" } } diff --git a/npm/cypress-schematic/src/builders/cypress/cypressBuilderOptions.ts b/npm/cypress-schematic/src/builders/cypress/cypressBuilderOptions.ts index bbbc51c88a..9194fa1ba2 100644 --- a/npm/cypress-schematic/src/builders/cypress/cypressBuilderOptions.ts +++ b/npm/cypress-schematic/src/builders/cypress/cypressBuilderOptions.ts @@ -2,7 +2,7 @@ import { JsonObject } from '@angular-devkit/core' export interface CypressBuilderOptions extends JsonObject { baseUrl: string - configFile: string | false + configFile: string browser: 'electron' | 'chrome' | 'chromium' | 'canary' | 'firefox' | 'edge' | string devServerTarget: string env: Record diff --git a/npm/cypress-schematic/src/builders/cypress/index.ts b/npm/cypress-schematic/src/builders/cypress/index.ts index 9e661c0472..8cb7457de6 100644 --- a/npm/cypress-schematic/src/builders/cypress/index.ts +++ b/npm/cypress-schematic/src/builders/cypress/index.ts @@ -79,7 +79,7 @@ function initCypress (userOptions: CypressBuilderOptions): Observable', + }, +}) diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json b/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json deleted file mode 100644 index 4426d4e7d7..0000000000 --- a/npm/cypress-schematic/src/schematics/ng-add/files/cypress.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "integrationFolder": "<%= root%>cypress/integration", - "supportFile": "<%= root%>cypress/support/index.ts", - "videosFolder": "<%= root%>cypress/videos", - "screenshotsFolder": "<%= root%>cypress/screenshots", - "pluginsFile": "<%= root%>cypress/plugins/index.ts", - "fixturesFolder": "<%= root%>cypress/fixtures", - "baseUrl": "<%= baseUrl%>" -} \ No newline at end of file diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/integration/spec.ts b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/e2e/spec.cy.ts similarity index 100% rename from npm/cypress-schematic/src/schematics/ng-add/files/cypress/integration/spec.ts rename to npm/cypress-schematic/src/schematics/ng-add/files/cypress/e2e/spec.cy.ts diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/fixtures/example.json b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/fixtures/example.json new file mode 100644 index 0000000000..20b22a17d3 --- /dev/null +++ b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io" +} + \ No newline at end of file diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/plugins/index.ts b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/plugins/index.ts deleted file mode 100644 index bfc9d3b65d..0000000000 --- a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/plugins/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress -// For more info, visit https://on.cypress.io/plugins-api -module.exports = (on, config) => {} diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/e2e.ts b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/e2e.ts new file mode 100644 index 0000000000..80a6b856d9 --- /dev/null +++ b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/e2e.ts @@ -0,0 +1,17 @@ +// *********************************************************** +// This example support/component.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// When a command from ./commands is ready to use, import with `import './commands'` syntax +// import './commands'; diff --git a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/index.ts b/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/index.ts deleted file mode 100644 index ac293b6165..0000000000 --- a/npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// When a command from ./commands is ready to use, import with `import './commands'` syntax -// import './commands'; diff --git a/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts b/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts index 0bf90878cb..eff647c20c 100644 --- a/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts +++ b/npm/cypress-schematic/src/schematics/ng-add/index.spec.ts @@ -1,7 +1,7 @@ /// import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing' -import { join, resolve } from 'path' +import { join } from 'path' import { expect } from 'chai' describe('@cypress/schematic: ng-add', () => { @@ -32,15 +32,15 @@ describe('@cypress/schematic: ng-add', () => { }) it('should create cypress files', async () => { - const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.ts', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json'] - const homePath = '/projects/sandbox/' - return schematicRunner.runSchematicAsync('ng-add', {}, appTree).toPromise().then((tree) => { - files.forEach((f) => { - const pathToFile = resolve(homePath, f) + const files = tree.files - expect(tree.exists(pathToFile), pathToFile).equal(true) - }) + expect(files).to.contain('/projects/sandbox/cypress/e2e/spec.cy.ts') + expect(files).to.contain('/projects/sandbox/cypress/support/e2e.ts') + expect(files).to.contain('/projects/sandbox/cypress/support/commands.ts') + expect(files).to.contain('/projects/sandbox/cypress/tsconfig.json') + expect(files).to.contain('/projects/sandbox/cypress.config.ts') + expect(files).to.contain('/projects/sandbox/cypress/fixtures/example.json') }) }) }) diff --git a/npm/cypress-schematic/src/schematics/ng-add/index.ts b/npm/cypress-schematic/src/schematics/ng-add/index.ts index 6d56862523..23979cd2c7 100644 --- a/npm/cypress-schematic/src/schematics/ng-add/index.ts +++ b/npm/cypress-schematic/src/schematics/ng-add/index.ts @@ -195,9 +195,7 @@ function modifyAngularJson (options: any): Rule { }, } - const configFile = projects[project].root - ? `${projects[project].root}/cypress.json` - : null + const configFile = getCypressConfigFile(angularJsonVal, project) if (configFile) { Object.assign(runJson.options, { configFile }) @@ -233,6 +231,17 @@ function modifyAngularJson (options: any): Rule { } } +export const getCypressConfigFile = (angularJsonVal: any, projectName: string) => { + const project = angularJsonVal.projects[projectName] + const tsConfig = project?.architect?.lint?.options?.tsConfig + + if (project.root) { + return `${project.root}/cypress.config.${tsConfig ? 'ts' : 'js'}` + } + + return null +} + export const addCypressTsConfig = (tree: Tree, angularJsonVal: any, projectName: string) => { const project = angularJsonVal.projects[projectName] let tsConfig = project?.architect?.lint?.options?.tsConfig diff --git a/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.spec.ts b/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.spec.ts index 28bc77f955..a5101d2f21 100644 --- a/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.spec.ts +++ b/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.spec.ts @@ -1,5 +1,7 @@ +/// + import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing' -import { join, resolve } from 'path' +import { join } from 'path' import { expect } from 'chai' describe('@cypress/schematic:e2e ng-generate', () => { @@ -15,7 +17,7 @@ describe('@cypress/schematic:e2e ng-generate', () => { version: '12.0.0', } - const appOptions = { + const appOptions: Parameters[2] = { name: 'sandbox', inlineTemplate: false, routing: false, @@ -28,16 +30,11 @@ describe('@cypress/schematic:e2e ng-generate', () => { appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'application', appOptions, appTree).toPromise() }) - it('should create cypress files', async () => { - const files = ['cypress/integration/foo.spec.ts'] - const homePath = '/projects/sandbox/' - + it('should create cypress spec file', async () => { return schematicRunner.runSchematicAsync('e2e', { name: 'foo' }, appTree).toPromise().then((tree) => { - files.forEach((f) => { - const pathToFile = resolve(homePath, f) + const files = tree.files - expect(tree.exists(pathToFile), pathToFile).equal(true) - }) + expect(files).to.contain('/projects/sandbox/cypress/e2e/foo.cy.ts') }) }) }) diff --git a/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.ts b/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.ts index cc499f34bf..1a68ad613e 100644 --- a/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.ts +++ b/npm/cypress-schematic/src/schematics/ng-generate/e2e/index.ts @@ -36,20 +36,24 @@ export default function (options: Schema): Rule { const host = createSpec(tree) const { workspace } = await workspaces.readWorkspace('/', host) - if (!options.project) { - // @ts-ignore - options.project = workspace.extensions.defaultProject - } + let project - //@ts-ignore - const project = workspace.projects.get(options.project) + if (!options.project) { + project = workspace.projects.get(workspace.extensions.defaultProject as string) + } else { + project = workspace.projects.get(options.project) + } if (!project) { throw new SchematicsException(`Invalid project name: ${options.project}`) } + if (options.name === undefined) { + throw new SchematicsException(`No file name specified. This is required to generate a new Cypress file.`) + } + if (options.path === undefined) { - options.path = `${project.root}/cypress/integration` + options.path = `${project.root}/cypress/e2e` } const templateSource = apply(url('../files/__path__'), [ diff --git a/npm/cypress-schematic/src/schematics/ng-generate/files/__path__/__name@dasherize__.spec.ts.template b/npm/cypress-schematic/src/schematics/ng-generate/files/__path__/__name@dasherize__.cy.ts.template similarity index 100% rename from npm/cypress-schematic/src/schematics/ng-generate/files/__path__/__name@dasherize__.spec.ts.template rename to npm/cypress-schematic/src/schematics/ng-generate/files/__path__/__name@dasherize__.cy.ts.template diff --git a/npm/design-system/cypress.config.js b/npm/design-system/cypress.config.js new file mode 100644 index 0000000000..15366b8828 --- /dev/null +++ b/npm/design-system/cypress.config.js @@ -0,0 +1,19 @@ +const { devServer } = require('@cypress/vite-dev-server') + +module.exports = { + viewportWidth: 1024, + viewportHeight: 800, + video: false, + projectId: 'z9dxah', + env: { + reactDevtools: true, + }, + fixturesFolder: false, + component: { + excludeSpecPattern: [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + ], + devServer, + }, +} diff --git a/npm/design-system/cypress.json b/npm/design-system/cypress.json deleted file mode 100644 index 00494ad9b7..0000000000 --- a/npm/design-system/cypress.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "viewportWidth": 1024, - "viewportHeight": 800, - "video": false, - "projectId": "z9dxah", - "testFiles": "**/*spec.{js,jsx,ts,tsx}", - "env": { - "reactDevtools": true - }, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "componentFolder": "src", - "fixturesFolder": false -} diff --git a/npm/design-system/cypress/plugins/index.js b/npm/design-system/cypress/plugins/index.js deleted file mode 100644 index 3c7a64d322..0000000000 --- a/npm/design-system/cypress/plugins/index.js +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check -const { startDevServer } = require('@cypress/vite-dev-server') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - on('dev-server:start', (options) => startDevServer({ options })) - - return config -} diff --git a/npm/design-system/cypress/support/component-index.html b/npm/design-system/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/design-system/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/design-system/cypress/support/component.js b/npm/design-system/cypress/support/component.js new file mode 100644 index 0000000000..5b956ef6e6 --- /dev/null +++ b/npm/design-system/cypress/support/component.js @@ -0,0 +1,14 @@ +import 'regenerator-runtime/runtime' +import 'cypress-real-events/support' +import '@percy/cypress' +import './storybook' +import 'normalize.css/normalize.css' + +// Need to register these once per app. Depending which components are consumed +// from @cypress/design-system, different icons are required. +import { library } from '@fortawesome/fontawesome-svg-core' +import { fab } from '@fortawesome/free-brands-svg-icons' +import { fas } from '@fortawesome/free-solid-svg-icons' + +library.add(fas) +library.add(fab) diff --git a/npm/design-system/cypress/support/index.js b/npm/design-system/cypress/support/index.js deleted file mode 100644 index 1ae4156515..0000000000 --- a/npm/design-system/cypress/support/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import 'regenerator-runtime/runtime' -import 'cypress-real-events/support' -import '@percy/cypress' -import './storybook' - -// Need to register these once per app. Depending which components are consumed -// from @cypress/design-system, different icons are required. -import { library } from '@fortawesome/fontawesome-svg-core' -import { fab } from '@fortawesome/free-brands-svg-icons' -import { fas } from '@fortawesome/free-solid-svg-icons' - -library.add(fas) -library.add(fab) diff --git a/npm/design-system/package.json b/npm/design-system/package.json index 99c9d35378..96ba0ea744 100644 --- a/npm/design-system/package.json +++ b/npm/design-system/package.json @@ -8,9 +8,9 @@ "build-prod": "yarn build", "build-storybook": "build-storybook", "build-style-types": "tsm \"src/css/derived/*.scss\" --nameFormat none --exportType default", - "cy:open": "node ../../scripts/cypress.js open-ct --project ${PWD}", + "cy:open": "node ../../scripts/cypress.js open --component --project ${PWD}", "cy:open:debug": "node --inspect-brk ../../scripts/start.js --component-testing --project ${PWD}", - "cy:run": "node ../../scripts/cypress.js run-ct --project ${PWD}", + "cy:run": "node ../../scripts/cypress.js run --component --project ${PWD}", "cy:run:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}", "storybook": "start-storybook -p 6006", "test": "yarn cy:run", @@ -19,11 +19,11 @@ "watch": "yarn build --watch" }, "dependencies": { - "@fortawesome/fontawesome-free": "^5.15.2", - "@fortawesome/fontawesome-svg-core": "^1.2.34", - "@fortawesome/free-brands-svg-icons": "^5.15.2", - "@fortawesome/free-solid-svg-icons": "^5.15.2", - "@fortawesome/react-fontawesome": "^0.1.14", + "@fortawesome/fontawesome-free": "^6.0.0", + "@fortawesome/fontawesome-svg-core": "^1.3.0", + "@fortawesome/free-brands-svg-icons": "^6.0.0", + "@fortawesome/free-solid-svg-icons": "^6.0.0", + "@fortawesome/react-fontawesome": "^0.1.17", "@iconify/icons-vscode-icons": "^1.1.4", "@iconify/react": "2.0.0-rc.8", "@iconify/types": "^1.0.6", @@ -75,17 +75,17 @@ "rollup-plugin-copy": "^3.4.0", "rollup-plugin-peer-deps-external": "2.2.4", "rollup-plugin-postcss": "^4.0.0", - "sass": "1.32.8", + "sass": "1.44.0", "sass-loader": "10.1.1", "style-loader": "^2.0.0", "svg-url-loader": "3.0.3", - "ts-node": "^9.1.1", + "ts-node": "^10.2.1", "tsc-alias": "^1.2.9", "tsconfig-paths-webpack-plugin": "^3.5.1", "typed-scss-modules": "^4.1.1", "typescript": "^4.2.3", - "vite": "2.2.3", - "webpack": "4.44.1" + "vite": "2.9.0-beta.3", + "webpack": "^4.44.2" }, "peerDependencies": { "react": "^=16.x || ^=17.x", diff --git a/npm/design-system/src/components/Nav/LeftNav.cy.tsx b/npm/design-system/src/components/Nav/LeftNav.cy.tsx new file mode 100644 index 0000000000..6d2650167d --- /dev/null +++ b/npm/design-system/src/components/Nav/LeftNav.cy.tsx @@ -0,0 +1,143 @@ +import * as React from 'react' +import { mount } from '@cypress/react' +import { library } from '@fortawesome/fontawesome-svg-core' +import { fab } from '@fortawesome/free-brands-svg-icons' +import { fas } from '@fortawesome/free-solid-svg-icons' + +import { mountAndSnapshot } from 'util/testing' +import { NavItem } from './types' +import { LeftNav } from './LeftNav' + +library.add(fas) +library.add(fab) + +const homeItem: NavItem = { + id: 'foo', + title: 'Foo button', + icon: 'home', + interaction: { + type: 'anchor', + href: 'https://cypress.io', + }, +} + +const makeOnClickItem: (options?: Partial) => NavItem = (options?: Partial) => { + return { + id: 'bar', + title: 'Bar button', + icon: 'key', + interaction: { + type: 'js', + onClick: () => { + }, + }, + ...options, + } +} + +const items = [homeItem, makeOnClickItem()] + +describe('LeftNav', () => { + it('renders', () => { + mount() + cy.get('nav').should('exist') + }) + + it('renders a stack of items', () => { + mountAndSnapshot() + + cy.get('nav').should('exist') + }) + + it('properly follows anchor links', () => { + mount() + + cy.get('a').first().eq(0).click().url().should('include', '#foo') + }) + + it('should properly display in page', () => { + const Comp = () => ( +
+ +
+ This is the main page content +
+
+ ) + + mount() + }) + + it('properly follows JS onclicks', () => { + const clickSpy = cy.spy() + + const Wrapper = () => { + const [activeIndex, setActiveIndex] = React.useState() + + const items = [ + homeItem, + makeOnClickItem({ + location: 'bottom', + id: 'bottom-item', + icon: 'ad', + interaction: { + type: 'js', + onClick ({ index }) { + if (index === activeIndex) { + return setActiveIndex(undefined) + } + + setActiveIndex(2) + }, + }, + }), + makeOnClickItem({ + itemClassesActive: 'second-item-button-active', + itemClasses: 'second-item-button', + interaction: { + type: 'js', + onClick ({ index }) { + if (index === activeIndex) { + return setActiveIndex(undefined) + } + + setActiveIndex(1) + clickSpy() + }, + }, + }), + ] + + return ( +
+ +
This is the main page content
+
+ ) + } + + mount() + + cy.get('a').eq(1).click().should(() => { + expect(clickSpy).to.be.called + }) + }) +}) diff --git a/npm/design-system/src/components/Nav/LeftNav.spec.tsx b/npm/design-system/src/components/Nav/LeftNav.spec.tsx deleted file mode 100644 index 96eeaf5393..0000000000 --- a/npm/design-system/src/components/Nav/LeftNav.spec.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import * as React from 'react' -import { mount } from '@cypress/react' -import { library } from '@fortawesome/fontawesome-svg-core' -import { fab } from '@fortawesome/free-brands-svg-icons' -import { fas } from '@fortawesome/free-solid-svg-icons' - -import { mountAndSnapshot } from 'util/testing' -import { NavItem } from './types' -import { LeftNav } from './LeftNav' - -library.add(fas) -library.add(fab) - -const homeItem: NavItem = { - id: 'foo', - title: 'Foo button', - icon: 'home', - interaction: { - type: 'anchor', - href: 'https://cypress.io', - }, -} - -const makeOnClickItem: (options?: Partial) => NavItem = (options?: Partial) => { - return { - id: 'bar', - title: 'Bar button', - icon: 'key', - interaction: { - type: 'js', - onClick: () => { - }, - }, - ...options, - } -} - -const items = [homeItem, makeOnClickItem()] - -describe('LeftNav', () => { - it('renders', () => { - mount() - cy.get('nav').should('exist') - }) - - it('renders a stack of items', () => { - mountAndSnapshot() - - cy.get('nav').should('exist') - }) - - it('properly follows anchor links', () => { - mount() - - cy.get('a').first().eq(0).click().url().should('include', '#foo') - }) - - it('should properly display in page', () => { - const Comp = () => ( -
- -
- This is the main page content -
-
- ) - - mount() - }) - - it('properly follows JS onclicks', () => { - const clickSpy = cy.spy() - - const Wrapper = () => { - const [activeIndex, setActiveIndex] = React.useState() - - const items = [ - homeItem, - makeOnClickItem({ - location: 'bottom', - id: 'bottom-item', - icon: 'ad', - interaction: { - type: 'js', - onClick (idx) { - if (idx === activeIndex) { - return setActiveIndex(undefined) - } - - setActiveIndex(2) - }, - }, - }), - makeOnClickItem({ - itemClassesActive: 'second-item-button-active', - itemClasses: 'second-item-button', - interaction: { - type: 'js', - onClick (idx) { - if (idx === activeIndex) { - return setActiveIndex(undefined) - } - - setActiveIndex(1) - clickSpy() - }, - }, - }), - ] - - return ( -
- -
This is the main page content
-
- ) - } - - mount() - - cy.get('a').eq(1).click().should(() => { - expect(clickSpy).to.be.called - }) - }) -}) diff --git a/npm/design-system/src/components/Playground.spec.tsx b/npm/design-system/src/components/Playground.cy.tsx similarity index 100% rename from npm/design-system/src/components/Playground.spec.tsx rename to npm/design-system/src/components/Playground.cy.tsx diff --git a/npm/design-system/src/components/collapsibleGroup/CollapsibleGroup.spec.tsx b/npm/design-system/src/components/collapsibleGroup/CollapsibleGroup.cy.tsx similarity index 100% rename from npm/design-system/src/components/collapsibleGroup/CollapsibleGroup.spec.tsx rename to npm/design-system/src/components/collapsibleGroup/CollapsibleGroup.cy.tsx diff --git a/npm/design-system/src/components/fileTree/FileTree.cy.tsx b/npm/design-system/src/components/fileTree/FileTree.cy.tsx new file mode 100644 index 0000000000..a99267cb3b --- /dev/null +++ b/npm/design-system/src/components/fileTree/FileTree.cy.tsx @@ -0,0 +1,132 @@ +import React from 'react' +import { mount } from '@cypress/react' +import { FileTree } from './FileTree' +import { mountAndSnapshot } from 'util/testing' + +const files = [ + { + path: 'foo/bar/foo.spec.js', + }, + { + path: 'qux/dog.spec.tsx', + }, + { + path: 'merp/cat.spec.ts', + }, +] + +const assertSelectedBorder = ($els: JQuery) => { + const win = $els[0].ownerDocument.defaultView + + if (win) { + const after = win.getComputedStyle($els[0], 'after') + + // Verify that we see at least some border, indicating it is highlighted + const leftStyle = after.getPropertyValue('border-left-style') + + expect(leftStyle).to.eq('solid') + + const leftWidth = after.getPropertyValue('border-left-width') + + expect(leftWidth).to.eq('2px') + } +} + +beforeEach(() => { + cy.viewport(500, 500) +}) + +describe('FileTree', () => { + it('should send onFilePress callback on space and enter', () => { + const filePressStub = cy.stub() + + mountAndSnapshot( +
+ +
, + ) + + // Click on the "foo" directory + cy.get('div').contains('foo').click() + + // navigate to "qux" + cy.focused().type('{downarrow}') + cy.get('div').contains('dog.spec.tsx').should('exist') + + // collapse "qux", hiding "dog.spec.tsx" + cy.focused().type('{enter}') + cy.get('div').contains('dog.spec.tsx').should('not.exist') + + // uncollapse "qux", revealing "dog.spec.tsx" + cy.focused().type('{enter}') + cy.get('div').contains('dog.spec.tsx').should('exist') + + // navigate to "dog.spec.tsx" + cy.focused().type('{downarrow}') + cy.focused().type(' ').then(() => { + expect(filePressStub).to.have.been.callCount(1) + }) + + cy.focused().type('{uparrow}') + cy.focused().type('{uparrow}') + + cy.focused().should('contain', 'foo/bar') + }) + + describe('focus', () => { + it('should automatically focus the first row when focused', () => { + mount( +
+ +
, + ) + + cy.get('[data-cy=virtualized-tree]').focus() + + cy.contains('.treeChild', '/').then(assertSelectedBorder) + }) + + it('should preserve focus state', () => { + mount( +
+
+ +
+ +
, + ) + + cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') + + cy.get('button').focus() + + cy.get('[data-cy=virtualized-tree]').focus() + + cy.contains('.treeChild', 'foo.spec.js').then(assertSelectedBorder) + }) + + it('should scroll to item on keyboard input', () => { + const files = [] + + for (let i = 0; i < 100; i++) { + files.push({ path: `File ${i}` }) + } + + mount( +
+ +
, + ) + + cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') + + cy.get('[data-cy=virtualized-tree] > div').scrollTo('bottom') + + cy.contains('.treeChild', 'File 99').should('be.visible') + + cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') + + cy.contains('.treeChild', 'File 3').should('be.visible') + }) + }) +}) diff --git a/npm/design-system/src/components/fileTree/FileTree.spec.tsx b/npm/design-system/src/components/fileTree/FileTree.spec.tsx deleted file mode 100644 index c3c193cbf9..0000000000 --- a/npm/design-system/src/components/fileTree/FileTree.spec.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import React from 'react' -import { mount } from '@cypress/react' -import { FileTree } from './FileTree' -import { mountAndSnapshot } from 'util/testing' - -const files = [ - { - path: 'foo/bar/foo.spec.js', - }, - { - path: 'qux/dog.spec.tsx', - }, - { - path: 'merp/cat.spec.ts', - }, -] - -const assertSelectedBorder = ($els: JQuery) => { - const win = $els[0].ownerDocument.defaultView - const after = win.getComputedStyle($els[0], 'after') - - // Verify that we see at least some border, indicating it is highlighted - const leftStyle = after.getPropertyValue('border-left-style') - - expect(leftStyle).to.eq('solid') - - const leftWidth = after.getPropertyValue('border-left-width') - - expect(leftWidth).to.eq('2px') -} - -beforeEach(() => { - cy.viewport(500, 500) -}) - -describe('FileTree', () => { - it('should send onFilePress callback on space and enter', () => { - const filePressStub = cy.stub() - - mountAndSnapshot( -
- -
, - ) - - // Click on the "foo" directory - cy.get('div').contains('foo').click() - - // navigate to "qux" - cy.focused().type('{downarrow}') - cy.get('div').contains('dog.spec.tsx').should('exist') - - // collapse "qux", hiding "dog.spec.tsx" - cy.focused().type('{enter}') - cy.get('div').contains('dog.spec.tsx').should('not.exist') - - // uncollapse "qux", revealing "dog.spec.tsx" - cy.focused().type('{enter}') - cy.get('div').contains('dog.spec.tsx').should('exist') - - // navigate to "dog.spec.tsx" - cy.focused().type('{downarrow}') - cy.focused().type(' ').then(() => { - expect(filePressStub).to.have.been.callCount(1) - }) - - cy.focused().type('{uparrow}') - cy.focused().type('{uparrow}') - - cy.focused().should('contain', 'foo/bar') - }) - - describe('focus', () => { - it('should automatically focus the first row when focused', () => { - mount( -
- -
, - ) - - cy.get('[data-cy=virtualized-tree]').focus() - - cy.contains('.treeChild', '/').then(assertSelectedBorder) - }) - - it('should preserve focus state', () => { - mount( -
-
- -
- -
, - ) - - cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') - - cy.get('button').focus() - - cy.get('[data-cy=virtualized-tree]').focus() - - cy.contains('.treeChild', 'foo.spec.js').then(assertSelectedBorder) - }) - - it('should scroll to item on keyboard input', () => { - const files = [] - - for (let i = 0; i < 100; i++) { - files.push({ path: `File ${i}` }) - } - - mount( -
- -
, - ) - - cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') - - cy.get('[data-cy=virtualized-tree] > div').scrollTo('bottom') - - cy.contains('.treeChild', 'File 99').should('be.visible') - - cy.get('[data-cy=virtualized-tree]').focus().type('{downarrow}').type('{downarrow}') - - cy.contains('.treeChild', 'File 3').should('be.visible') - }) - }) -}) diff --git a/npm/design-system/src/components/searchInput/SearchInput.cy.tsx b/npm/design-system/src/components/searchInput/SearchInput.cy.tsx new file mode 100644 index 0000000000..c18aaba825 --- /dev/null +++ b/npm/design-system/src/components/searchInput/SearchInput.cy.tsx @@ -0,0 +1,76 @@ +import * as React from 'react' +import { mount } from '@cypress/react' + +import { SearchInput } from './SearchInput' +import { mountAndSnapshot } from 'util/testing' + +const { useCallback, useState } = React + +describe('SearchInput', () => { + const StatefulWrapper: React.FC<{onInput?: (input: string) => void}> = ({ onInput }) => { + const [value, setValue] = useState('') + + const memoedOnInput = useCallback((input: string) => { + setValue(input) + onInput?.(input) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return + } + + it('should render', () => { + function onInput () {} + mountAndSnapshot() + cy.get('input').should('exist') + }) + + it('should pass input to onInput', () => { + const onInput = cy.stub() + + mount() + + const string = 'Testing input!' + + cy.get('input').type(string).then(() => { + expect(onInput).to.be.callCount(string.length) + + for (let i = 0; i < string.length; i++) { + expect(onInput.getCall(i)).to.be.calledWithExactly(string.slice(0, i + 1)) + } + }) + }) + + describe('Clear button', () => { + it('should only show when text is present', () => { + mount() + + cy.get('[aria-label="Clear search"]').should('not.exist') + + cy.get('input').type('some input') + + cy.get('[aria-label="Clear search"]').should('exist') + + cy.percySnapshot() + }) + + it('should clear input on click', () => { + const onInput = cy.stub() + + mount() + + cy.get('input').should('have.value', 'a value') + + cy.get('[aria-label="Clear search"]').click().then(() => expect(onInput).to.be.calledOnceWith('')) + }) + + it('should focus input on click', () => { + function onInput () {} + mount() + + cy.get('[aria-label="Clear search"]').click() + + cy.get('input').should('be.focused') + }) + }) +}) diff --git a/npm/design-system/src/components/searchInput/SearchInput.spec.tsx b/npm/design-system/src/components/searchInput/SearchInput.spec.tsx deleted file mode 100644 index a91f97c649..0000000000 --- a/npm/design-system/src/components/searchInput/SearchInput.spec.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import * as React from 'react' -import { mount } from '@cypress/react' - -import { SearchInput } from './SearchInput' -import { useCallback, useState } from 'react' -import { mountAndSnapshot } from 'util/testing' - -describe('SearchInput', () => { - const StatefulWrapper: React.FC<{onInput?: (input: string) => void}> = ({ onInput }) => { - const [value, setValue] = useState('') - - const memoedOnInput = useCallback((input: string) => { - setValue(input) - onInput?.(input) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - return - } - - it('should render', () => { - mountAndSnapshot( {}} />) - cy.get('input').should('exist') - }) - - it('should pass input to onInput', () => { - const onInput = cy.stub() - - mount() - - const string = 'Testing input!' - - cy.get('input').type(string).then(() => { - expect(onInput).to.be.callCount(string.length) - - for (let i = 0; i < string.length; i++) { - expect(onInput.getCall(i)).to.be.calledWithExactly(string.slice(0, i + 1)) - } - }) - }) - - describe('Clear button', () => { - it('should only show when text is present', () => { - mount() - - cy.get('[aria-label="Clear search"]').should('not.exist') - - cy.get('input').type('some input') - - cy.get('[aria-label="Clear search"]').should('exist') - - cy.percySnapshot() - }) - - it('should clear input on click', () => { - const onInput = cy.stub() - - mount() - - cy.get('input').should('have.value', 'a value') - - cy.get('[aria-label="Clear search"]').click().then(() => expect(onInput).to.be.calledOnceWith('')) - }) - - it('should focus input on click', () => { - mount( {}} />) - - cy.get('[aria-label="Clear search"]').click() - - cy.get('input').should('be.focused') - }) - }) -}) diff --git a/npm/design-system/src/components/searchInput/SearchInput.stories.tsx b/npm/design-system/src/components/searchInput/SearchInput.stories.tsx index 0325bb8771..a9a2d5e2bd 100644 --- a/npm/design-system/src/components/searchInput/SearchInput.stories.tsx +++ b/npm/design-system/src/components/searchInput/SearchInput.stories.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import { createStory, createStorybookConfig } from 'stories/util' import { SearchInput as SearchInputComponent } from './SearchInput' -import { useState } from 'react' +const { useState } = React export default createStorybookConfig({ title: 'Components/SearchInput', diff --git a/npm/design-system/src/components/virtualizedTree/VirtualizedTree.spec.tsx b/npm/design-system/src/components/virtualizedTree/VirtualizedTree.cy.tsx similarity index 100% rename from npm/design-system/src/components/virtualizedTree/VirtualizedTree.spec.tsx rename to npm/design-system/src/components/virtualizedTree/VirtualizedTree.cy.tsx diff --git a/npm/design-system/src/core/button/Button.spec.tsx b/npm/design-system/src/core/button/Button.cy.tsx similarity index 100% rename from npm/design-system/src/core/button/Button.spec.tsx rename to npm/design-system/src/core/button/Button.cy.tsx diff --git a/npm/design-system/src/core/button/Button.stories.tsx b/npm/design-system/src/core/button/Button.stories.tsx index ddf523bc93..1a484a53f1 100644 --- a/npm/design-system/src/core/button/Button.stories.tsx +++ b/npm/design-system/src/core/button/Button.stories.tsx @@ -1,5 +1,7 @@ import * as React from 'react' -import { action } from '@storybook/addon-actions' +// TODO: This is causing a "module not defined error" +// Find out why and fix it +// import { action } from '@storybook/addon-actions' import { createStory, createStorybookConfig } from 'stories/util' @@ -11,6 +13,9 @@ import { TextSize } from 'css' import { PaddedBox } from '../surface/paddedBox/PaddedBox' import { Icon } from '../icon/Icon' +// stub it for now +const action = (action: string) => undefined + export default createStorybookConfig({ title: 'Core/Button', }) diff --git a/npm/design-system/src/core/button/Button.tsx b/npm/design-system/src/core/button/Button.tsx index 556b3da5a5..2de0b6ba71 100644 --- a/npm/design-system/src/core/button/Button.tsx +++ b/npm/design-system/src/core/button/Button.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useRef, RefObject } from 'react' +import type { RefObject } from 'react' import cs from 'classnames' import { useButton } from '@react-aria/button' @@ -11,6 +11,8 @@ import styles from './Button.module.scss' import { FocusRing } from '@react-aria/focus' import { focusClass } from 'css/derived/util' +const { useRef } = React + interface SharedButtonProps extends TextSizableComponent { /** * Defaults to 'blue' diff --git a/npm/design-system/src/core/icon/Icon.cy.tsx b/npm/design-system/src/core/icon/Icon.cy.tsx new file mode 100644 index 0000000000..92ae10bf54 --- /dev/null +++ b/npm/design-system/src/core/icon/Icon.cy.tsx @@ -0,0 +1,32 @@ +import * as React from 'react' +import { Icon } from './Icon' +import { mountAndSnapshot } from 'util/testing' + +import styles from './Icon.stories.module.scss' +import { iconLines } from './Icon.stories' + +// TODO: Autogenerate from stories +describe('', () => { + it('Standard icons', () => { + const Icons = () => ( +
+ + + + +
+ ) + + mountAndSnapshot() + }) + + it('Icon lines', () => { + const Icons = () => ( + <> + {iconLines(['text-xs', 'text-s', 'text-ms', 'text-m', 'text-ml', 'text-l', 'text-xl', 'text-2xl', 'text-3xl', 'text-4xl'])} + + ) + + mountAndSnapshot() + }) +}) diff --git a/npm/design-system/src/core/icon/Icon.spec.tsx b/npm/design-system/src/core/icon/Icon.spec.tsx deleted file mode 100644 index 7676903d57..0000000000 --- a/npm/design-system/src/core/icon/Icon.spec.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react' -import { Icon } from './Icon' -import { mountAndSnapshot } from 'util/testing' - -import styles from './Icon.stories.module.scss' -import { iconLines } from './Icon.stories' - -// TODO: Autogenerate from stories -describe('', () => { - it('Standard icons', () => { - const Icons = () => ( -
- - - - -
- ) - - mountAndSnapshot() - }) - - it('Icon lines', () => { - const Icons = () => iconLines(['text-xs', 'text-s', 'text-ms', 'text-m', 'text-ml', 'text-l', 'text-xl', 'text-2xl', 'text-3xl', 'text-4xl']) - - mountAndSnapshot() - }) -}) diff --git a/npm/design-system/src/core/icon/Icon.tsx b/npm/design-system/src/core/icon/Icon.tsx index d7974f9718..58b2f2dd63 100644 --- a/npm/design-system/src/core/icon/Icon.tsx +++ b/npm/design-system/src/core/icon/Icon.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { SVGAttributes } from 'react' +import type { SVGAttributes } from 'react' import cs from 'classnames' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' diff --git a/npm/design-system/src/core/input/IconInput.tsx b/npm/design-system/src/core/input/IconInput.tsx index f5db23d8c0..37e4d904fa 100644 --- a/npm/design-system/src/core/input/IconInput.tsx +++ b/npm/design-system/src/core/input/IconInput.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { RefAttributes } from 'react' +import type { RefAttributes } from 'react' import cs from 'classnames' import { useFocusRing } from '@react-aria/focus' import { PressEvent } from '@react-types/shared' @@ -23,7 +23,7 @@ export type IconSettings = { ['aria-label']: string } | { onPress?: undefined - ['aria-label']?: undefined + ['aria-label']?: string | undefined }) export type IconInputProps = InputProps<{ diff --git a/npm/design-system/src/core/input/Input.cy.tsx b/npm/design-system/src/core/input/Input.cy.tsx new file mode 100644 index 0000000000..60cc344a86 --- /dev/null +++ b/npm/design-system/src/core/input/Input.cy.tsx @@ -0,0 +1,31 @@ +import * as React from 'react' +import { composeStories } from '@storybook/testing-react' +import * as stories from './Input.stories' +import { mountAndSnapshot } from 'util/testing' +// import { iconSizesWithSizes } from './Input.stories' + +const { + Input, + // Icon +} = composeStories(stories) + +// TODO: Autogenerate from stories +describe('', () => { + it('Standard input', () => { + mountAndSnapshot() + }) + + it('IconInput', () => { + // mountAndSnapshot() + }) + + // it('IconInput sizes', () => { + // const IconInput = () => ( + // <> + // {iconSizesWithSizes(['xs', 's', 'ms', 'm', 'ml', 'l', 'xl', '2xl'])} + // + // ) + + // mountAndSnapshot() + // }) +}) diff --git a/npm/design-system/src/core/input/Input.spec.tsx b/npm/design-system/src/core/input/Input.spec.tsx deleted file mode 100644 index 2fe6ae783a..0000000000 --- a/npm/design-system/src/core/input/Input.spec.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react' -import { composeStories } from '@storybook/testing-react' -import * as stories from './Input.stories' -import { mountAndSnapshot } from 'util/testing' -import { iconSizesWithSizes } from './Input.stories' - -const { Input, Icon } = composeStories(stories) - -// TODO: Autogenerate from stories -describe('', () => { - it('Standard input', () => { - mountAndSnapshot() - }) - - it('IconInput', () => { - mountAndSnapshot() - }) - - it('IconInput sizes', () => { - const IconInput = () => ( - <> - {iconSizesWithSizes(['xs', 's', 'ms', 'm', 'ml', 'l', 'xl', '2xl'])} - - ) - - mountAndSnapshot() - }) -}) diff --git a/npm/design-system/src/core/input/Input.stories.tsx b/npm/design-system/src/core/input/Input.stories.tsx index a4b1aac173..ec5d47397f 100644 --- a/npm/design-system/src/core/input/Input.stories.tsx +++ b/npm/design-system/src/core/input/Input.stories.tsx @@ -1,14 +1,18 @@ import * as React from 'react' -import { action } from '@storybook/addon-actions' +// TODO: This is causing a "module not defined error" +// Find out why and fix it +// import { action } from '@storybook/addon-actions' -import { createStory, createStorybookConfig } from 'stories/util' +import { createStory, createStorybookConfig } from '../../stories/util' import { Input as InputComponent } from './Input' import { IconInput as IconInputComponent } from './IconInput' -import typography from 'css/derived/jsTypography.scss' import { TextSize } from 'css' +// stub it for now +const action = (action: string) => undefined + export default createStorybookConfig({ title: 'Core/Input', excludeStories: ['iconSizesWithSizes'], @@ -38,12 +42,12 @@ export const Icon = createStory(() => ( label={{ type: 'aria', contents: 'full width input' }} prefixIcon={{ icon: 'home', - onPress: action('onPrefixClick'), + // onPress: action('onPrefixClick'), 'aria-label': 'onPrefixClick', }} suffixIcon={{ icon: 'times', - onPress: action('onSuffixClick'), + // onPress: action('onSuffixClick'), 'aria-label': 'onSuffixClick', }} /> @@ -53,7 +57,7 @@ export const Icon = createStory(() => ( label={{ type: 'aria', contents: '500px width input' }} suffixIcon={{ icon: 'times', - onPress: action('onSuffixClick'), + // onPress: action('onSuffixClick'), 'aria-label': 'onSuffixClick', }} value="This is a very long string in an IconInput. This displays the padding on the input section" @@ -62,7 +66,7 @@ export const Icon = createStory(() => ( label={{ type: 'aria', contents: '500px width input' }} prefixIcon={{ icon: 'home', - onPress: action('onPrefixClick'), + // onPress: action('onPrefixClick'), 'aria-label': 'onPrefixClick', }} value="This is a very long string in an IconInput. This displays the padding on the input section" @@ -74,12 +78,12 @@ export const Icon = createStory(() => ( }} prefixIcon={{ icon: 'home', - onPress: action('onPrefixClick'), + // onPress: action('onPrefixClick'), 'aria-label': 'onPrefixClick', }} suffixIcon={{ icon: 'times', - onPress: action('onSuffixClick'), + // onPress: action('onSuffixClick'), 'aria-label': 'onSuffixClick', }} /> @@ -90,7 +94,7 @@ export const Icon = createStory(() => ( }} suffixIcon={{ icon: 'times', - onPress: action('onSuffixClick'), + // onPress: action('onSuffixClick'), 'aria-label': 'onSuffixClick', }} placeholder="The leading icon isn't a button" @@ -99,7 +103,7 @@ export const Icon = createStory(() => ( label={{ type: 'aria', contents: 'leading button only' }} prefixIcon={{ icon: 'home', - onPress: action('onPrefixClick'), + // onPress: action('onPrefixClick'), 'aria-label': 'onPrefixClick', }} suffixIcon={{ @@ -133,10 +137,10 @@ export const iconSizesWithSizes = (sizes: string[]) => sizes.map((key) => { ) }) -export const IconSizes = createStory(() => ( -
-
- {iconSizesWithSizes(Object.keys(typography).filter((key) => key !== 'type' && !key.startsWith('line-height') && !key.startsWith('text-mono') && key !== 'text-3xl' && key !== 'text-4xl'))} -
-
-)) +// export const IconSizes = createStory(() => ( +//
+//
+// {iconSizesWithSizes(Object.keys(typography).filter((key) => key !== 'type' && !key.startsWith('line-height') && !key.startsWith('text-mono') && key !== 'text-3xl' && key !== 'text-4xl'))} +//
+//
+// )) diff --git a/npm/design-system/src/core/input/InputBase.tsx b/npm/design-system/src/core/input/InputBase.tsx index 5f49c24444..e23bfb404c 100644 --- a/npm/design-system/src/core/input/InputBase.tsx +++ b/npm/design-system/src/core/input/InputBase.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { CSSProperties, InputHTMLAttributes, MutableRefObject, ReactNode, RefObject, TextareaHTMLAttributes, useMemo, useRef } from 'react' +import type { CSSProperties, InputHTMLAttributes, MutableRefObject, ReactNode, RefObject, TextareaHTMLAttributes } from 'react' import { useTextField } from 'react-aria' import cs from 'classnames' @@ -11,6 +11,8 @@ import { SizingProps } from 'core/shared' import styles from './InputBase.module.scss' import { useCombinedRefs } from 'hooks/useCombinedRefs' +const { useMemo, useRef } = React + export interface SharedInputBaseProps extends SizingProps, Omit, 'size'> { inputRef?: MutableRefObject | null diff --git a/npm/design-system/src/core/surface/elevation/Elevation.spec.tsx b/npm/design-system/src/core/surface/elevation/Elevation.cy.tsx similarity index 100% rename from npm/design-system/src/core/surface/elevation/Elevation.spec.tsx rename to npm/design-system/src/core/surface/elevation/Elevation.cy.tsx diff --git a/npm/design-system/src/core/surface/paddedBox/PaddedBox.spec.tsx b/npm/design-system/src/core/surface/paddedBox/PaddedBox.cy.tsx similarity index 100% rename from npm/design-system/src/core/surface/paddedBox/PaddedBox.spec.tsx rename to npm/design-system/src/core/surface/paddedBox/PaddedBox.cy.tsx diff --git a/npm/design-system/src/core/surface/paddedBox/PaddedBox.tsx b/npm/design-system/src/core/surface/paddedBox/PaddedBox.tsx index 2d17328cf8..55ab20160a 100644 --- a/npm/design-system/src/core/surface/paddedBox/PaddedBox.tsx +++ b/npm/design-system/src/core/surface/paddedBox/PaddedBox.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { CSSProperties } from 'react' +import type { CSSProperties } from 'react' import cs from 'classnames' import { Spacing } from 'css' diff --git a/npm/design-system/src/core/text/placeholder/Placeholder.spec.tsx b/npm/design-system/src/core/text/placeholder/Placeholder.cy.tsx similarity index 100% rename from npm/design-system/src/core/text/placeholder/Placeholder.spec.tsx rename to npm/design-system/src/core/text/placeholder/Placeholder.cy.tsx diff --git a/npm/design-system/src/core/text/styledText/StyledText.spec.tsx b/npm/design-system/src/core/text/styledText/StyledText.cy.tsx similarity index 100% rename from npm/design-system/src/core/text/styledText/StyledText.spec.tsx rename to npm/design-system/src/core/text/styledText/StyledText.cy.tsx diff --git a/npm/design-system/src/core/text/styledText/StyledText.tsx b/npm/design-system/src/core/text/styledText/StyledText.tsx index 5ecd6f2781..b0569292a1 100644 --- a/npm/design-system/src/core/text/styledText/StyledText.tsx +++ b/npm/design-system/src/core/text/styledText/StyledText.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { CSSProperties } from 'react' +import type { CSSProperties } from 'react' import cs from 'classnames' import { LineHeight, TextSize } from 'css' diff --git a/npm/design-system/src/css/func.scss b/npm/design-system/src/css/func.scss index 3e921dad68..1a570db164 100644 --- a/npm/design-system/src/css/func.scss +++ b/npm/design-system/src/css/func.scss @@ -7,6 +7,8 @@ * @return {String} - Updated string */ // Taken from https://gist.github.com/PuddingNL/51866d4b9f1151963fbd973bf1d66116 +@use "sass:math"; + @function str-replace($string, $search, $replace: '') { $index: str-index($string, $search); @@ -18,5 +20,5 @@ } @function change-rem-unit-to-em($number) { - @return ($number / 1rem) + 0em; + @return math.div($number, 1rem) + 0em; } \ No newline at end of file diff --git a/npm/design-system/src/global.scss b/npm/design-system/src/global.scss index 9be2d9a57f..cffe798d9f 100644 --- a/npm/design-system/src/global.scss +++ b/npm/design-system/src/global.scss @@ -4,8 +4,6 @@ @use 'derived/export.scss'; @use 'typography'; -@use 'normalize.css/normalize.css'; - // probably should leave this for the consumer to set? body, html { font-size: typography.text(m); diff --git a/npm/design-system/src/hooks/useCombinedRefs.ts b/npm/design-system/src/hooks/useCombinedRefs.ts index 250f8092b8..0f26efd522 100644 --- a/npm/design-system/src/hooks/useCombinedRefs.ts +++ b/npm/design-system/src/hooks/useCombinedRefs.ts @@ -1,4 +1,5 @@ -import { MutableRefObject, RefCallback, useEffect } from 'react' +import type { MutableRefObject, RefCallback } from 'react' +import { useEffect } from 'react' /** * Joins the `externalRef` to receive the same boxed value as `localRef` diff --git a/npm/eslint-plugin-dev/lib/index.js b/npm/eslint-plugin-dev/lib/index.js index a1e3c1153a..8cd28a0572 100644 --- a/npm/eslint-plugin-dev/lib/index.js +++ b/npm/eslint-plugin-dev/lib/index.js @@ -116,7 +116,7 @@ const baseRules = { 'no-unneeded-ternary': 'error', 'no-unreachable': 'error', 'no-unused-labels': 'error', - 'no-unused-vars': ['error', { args: 'none' }], + 'no-unused-vars': ['error', { args: 'none', ignoreRestSiblings: true }], 'no-useless-concat': 'error', 'no-useless-constructor': 'error', 'no-var': 'error', @@ -261,6 +261,7 @@ module.exports = { files: [ '*.ts', '*.tsx', + '*.vue', ], parser: '@typescript-eslint/parser', plugins: [ @@ -270,10 +271,18 @@ module.exports = { 'no-undef': 'off', 'no-unused-vars': 'off', 'indent': 'off', + 'no-useless-constructor': 'off', + 'no-duplicate-imports': 'off', + 'import/no-duplicates': 'off', + '@typescript-eslint/no-duplicate-imports': [ + 'error', + ], '@typescript-eslint/no-unused-vars': [ 'error', { 'args': 'none', + 'ignoreRestSiblings': true, + 'argsIgnorePattern': '^_', }, ], '@typescript-eslint/type-annotation-spacing': 'error', diff --git a/npm/eslint-plugin-dev/package.json b/npm/eslint-plugin-dev/package.json index 35344ec2e1..f01cdbb88b 100644 --- a/npm/eslint-plugin-dev/package.json +++ b/npm/eslint-plugin-dev/package.json @@ -21,8 +21,8 @@ "eslint-plugin-json-format": "^2.0.0", "eslint-plugin-mocha": "^8.1.0", "eslint-plugin-promise": "^4.2.1", - "jest": "^24.8.0", - "jest-cli": "^24.8.0", + "jest": "^24.9.0", + "jest-cli": "^24.9.0", "sinon": "^7.3.2", "sinon-chai": "^3.3.0" }, diff --git a/npm/mount-utils/package.json b/npm/mount-utils/package.json index 271d0b2571..5dc38055b8 100644 --- a/npm/mount-utils/package.json +++ b/npm/mount-utils/package.json @@ -4,8 +4,10 @@ "description": "Shared utilities for the various component testing adapters", "main": "dist/index.js", "scripts": { - "build": "tsc", - "build-prod": "tsc", + "build": "tsc || echo 'built, with type errors'", + "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", + "build-prod": "yarn build", + "check-ts": "tsc --noEmit", "watch": "tsc -w" }, "dependencies": {}, diff --git a/npm/mount-utils/src/index.ts b/npm/mount-utils/src/index.ts index 64d15bed0d..94b70c1410 100644 --- a/npm/mount-utils/src/index.ts +++ b/npm/mount-utils/src/index.ts @@ -37,7 +37,17 @@ export interface StyleOptions { cssFile: string | string[] } -export const ROOT_ID = '__cy_root' +export const ROOT_SELECTOR = '[data-cy-root]' + +export const getContainerEl = (): HTMLElement => { + const el = document.querySelector(ROOT_SELECTOR) + + if (el) { + return el + } + + throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please use the mount utils to mount it properly`) +} /** * Remove any style or extra link elements from the iframe placeholder @@ -131,7 +141,7 @@ export const injectStylesBeforeElement = ( options: Partial, document: Document, el: HTMLElement | null, -) => { +): HTMLElement => { if (!el) return // first insert all stylesheets as Link elements diff --git a/npm/react/CHANGELOG.md b/npm/react/CHANGELOG.md index 2049bff392..2f9eb3a5f7 100644 --- a/npm/react/CHANGELOG.md +++ b/npm/react/CHANGELOG.md @@ -289,7 +289,7 @@ * Added the need to install a preprocessor or a dev-server plugin * Removed the pre-instalation of test coverage - * Install it manually by following [the documentation](https://docs.cypress.io/guides/tooling/code-coverage.html#Introduction) + * Install it manually by following [the documentation](https://on.cypress.io/code-coverage-introduction) * removed the pre-installation of `cypress-react-selector` * If you use `cy.react()` in your tests, the command will not work anymore. [Install it back in your support file](https://www.npmjs.com/package/cypress-react-selector) diff --git a/npm/react/README.md b/npm/react/README.md index 0da14ea143..23991e15c5 100644 --- a/npm/react/README.md +++ b/npm/react/README.md @@ -84,11 +84,13 @@ module.exports = (on, config) => { See [Recipes](./docs/recipes.md) for more examples. -2. You can specify where component spec files are located. For example, to have them located in `src` folder use: +2. You can specify a glob to locate component spec files. For example, to have them located in `src` folder use: ```json { - "componentFolder": "src" + "component": { + "specPattern": "src/**/*.cy.jsx" + } } ``` diff --git a/npm/react/cypress.config.js b/npm/react/cypress.config.js new file mode 100644 index 0000000000..ba560c3030 --- /dev/null +++ b/npm/react/cypress.config.js @@ -0,0 +1,79 @@ +// @ts-check +const { devServer } = require('@cypress/webpack-dev-server') + +module.exports = { + 'viewportWidth': 400, + 'viewportHeight': 400, + 'video': false, + 'projectId': 'z9dxah', + 'env': { + 'reactDevtools': true, + }, + 'experimentalFetchPolyfill': true, + 'component': { + 'excludeSpecPattern': [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + 'examples/**/*', + ], + devServer (cypressDevServerConfig, devServerConfig) { + const path = require('path') + const babelConfig = require('./babel.config.js') + + const webpackConfig = { + resolve: { + extensions: ['.js', '.ts', '.jsx', '.tsx'], + }, + mode: 'development', + devtool: false, + output: { + publicPath: '/', + chunkFilename: '[name].bundle.js', + }, + module: { + rules: [ + { + test: /\.(js|jsx|mjs|ts|tsx)$/, + loader: 'babel-loader', + options: { ...babelConfig, cacheDirectory: path.resolve(__dirname, '..', '..', '.babel-cache') }, + }, + { + test: /\.modules\.css$/i, + exclude: [/node_modules/], + use: [ + 'style-loader', + { + loader: 'css-loader', + options: { + modules: true, + }, + }, + ], + }, + { + test: /\.css$/, + exclude: [/node_modules/, /\.modules\.css$/i], + use: ['style-loader', 'css-loader'], + }, + { + // some of our examples import SVG + test: /\.svg$/, + loader: 'svg-url-loader', + }, + { + // some of our examples import SVG + test: /\.svg$/, + loader: 'svg-url-loader', + }, + { + test: /\.(png|jpg)$/, + use: ['file-loader'], + }, + ], + }, + } + + return devServer(cypressDevServerConfig, { webpackConfig }) + }, + }, +} diff --git a/npm/react/cypress.json b/npm/react/cypress.json deleted file mode 100644 index a6b5db93e7..0000000000 --- a/npm/react/cypress.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "viewportWidth": 400, - "viewportHeight": 400, - "video": false, - "projectId": "z9dxah", - "testFiles": "**/*spec.{js,jsx,ts,tsx}", - "env": { - "reactDevtools": true - }, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "experimentalFetchPolyfill": true -} \ No newline at end of file diff --git a/npm/react/cypress/component/advanced/api-test/spec.js b/npm/react/cypress/component/advanced/api-test/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/api-test/spec.js rename to npm/react/cypress/component/advanced/api-test/spec.cy.js diff --git a/npm/react/cypress/component/advanced/app-action-example/counter-spec.js b/npm/react/cypress/component/advanced/app-action-example/counter.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/app-action-example/counter-spec.js rename to npm/react/cypress/component/advanced/app-action-example/counter.cy.js diff --git a/npm/react/cypress/component/advanced/context/App-spec.js b/npm/react/cypress/component/advanced/context/App.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/context/App-spec.js rename to npm/react/cypress/component/advanced/context/App.cy.js diff --git a/npm/react/cypress/component/advanced/context/Mock-context-spec.js b/npm/react/cypress/component/advanced/context/Mock-context.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/context/Mock-context-spec.js rename to npm/react/cypress/component/advanced/context/Mock-context.cy.js diff --git a/npm/react/cypress/component/advanced/custom-command/spec.js b/npm/react/cypress/component/advanced/custom-command/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/custom-command/spec.js rename to npm/react/cypress/component/advanced/custom-command/spec.cy.js diff --git a/npm/react/cypress/component/advanced/forward-ref/forward-ref.spec.js b/npm/react/cypress/component/advanced/forward-ref/forward-ref.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/forward-ref/forward-ref.spec.js rename to npm/react/cypress/component/advanced/forward-ref/forward-ref.cy.js diff --git a/npm/react/cypress/component/advanced/framer-motion/Motion.spec.tsx b/npm/react/cypress/component/advanced/framer-motion/Motion.cy.tsx similarity index 100% rename from npm/react/cypress/component/advanced/framer-motion/Motion.spec.tsx rename to npm/react/cypress/component/advanced/framer-motion/Motion.cy.tsx diff --git a/npm/react/cypress/component/advanced/hooks/counter-with-hooks.spec.js b/npm/react/cypress/component/advanced/hooks/counter-with-hooks.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/hooks/counter-with-hooks.spec.js rename to npm/react/cypress/component/advanced/hooks/counter-with-hooks.cy.js diff --git a/npm/react/cypress/component/advanced/hooks/counter2-with-hooks.spec.js b/npm/react/cypress/component/advanced/hooks/counter2-with-hooks.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/hooks/counter2-with-hooks.spec.js rename to npm/react/cypress/component/advanced/hooks/counter2-with-hooks.cy.js diff --git a/npm/react/cypress/component/advanced/hooks/use-counter.spec.js b/npm/react/cypress/component/advanced/hooks/use-counter.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/hooks/use-counter.spec.js rename to npm/react/cypress/component/advanced/hooks/use-counter.cy.js diff --git a/npm/react/cypress/component/advanced/i18n/i18next-spec.js b/npm/react/cypress/component/advanced/i18n/i18next.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/i18n/i18next-spec.js rename to npm/react/cypress/component/advanced/i18n/i18next.cy.js diff --git a/npm/react/cypress/component/advanced/lazy-loaded-suspense/lazy-loaded-suspense.spec.tsx b/npm/react/cypress/component/advanced/lazy-loaded-suspense/lazy-loaded-suspense.cy.tsx similarity index 100% rename from npm/react/cypress/component/advanced/lazy-loaded-suspense/lazy-loaded-suspense.spec.tsx rename to npm/react/cypress/component/advanced/lazy-loaded-suspense/lazy-loaded-suspense.cy.tsx diff --git a/npm/react/cypress/component/advanced/lazy-loaded/app-spec.js b/npm/react/cypress/component/advanced/lazy-loaded/app.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/lazy-loaded/app-spec.js rename to npm/react/cypress/component/advanced/lazy-loaded/app.cy.js diff --git a/npm/react/cypress/component/advanced/lazy-loaded/lazy-load-spec.js b/npm/react/cypress/component/advanced/lazy-loaded/lazy-load.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/lazy-loaded/lazy-load-spec.js rename to npm/react/cypress/component/advanced/lazy-loaded/lazy-load.cy.js diff --git a/npm/react/cypress/component/advanced/lazy-loaded/other-spec.js b/npm/react/cypress/component/advanced/lazy-loaded/other.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/lazy-loaded/other-spec.js rename to npm/react/cypress/component/advanced/lazy-loaded/other.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/autocomplete-spec.js b/npm/react/cypress/component/advanced/material-ui-example/autocomplete.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/autocomplete-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/autocomplete.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/button-spec.js b/npm/react/cypress/component/advanced/material-ui-example/button.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/button-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/button.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/checkbox-labels-spec.js b/npm/react/cypress/component/advanced/material-ui-example/checkbox-labels.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/checkbox-labels-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/checkbox-labels.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/list-item-spec.js b/npm/react/cypress/component/advanced/material-ui-example/list-item.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/list-item-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/list-item.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/select-spec.js b/npm/react/cypress/component/advanced/material-ui-example/select.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/select-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/select.cy.js diff --git a/npm/react/cypress/component/advanced/material-ui-example/simple-rating-spec.js b/npm/react/cypress/component/advanced/material-ui-example/simple-rating.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/material-ui-example/simple-rating-spec.js rename to npm/react/cypress/component/advanced/material-ui-example/simple-rating.cy.js diff --git a/npm/react/cypress/component/advanced/mobx-v6/timer-spec.jsx b/npm/react/cypress/component/advanced/mobx-v6/timer.cy.jsx similarity index 100% rename from npm/react/cypress/component/advanced/mobx-v6/timer-spec.jsx rename to npm/react/cypress/component/advanced/mobx-v6/timer.cy.jsx diff --git a/npm/react/cypress/component/advanced/mock-fetch/fetch-spec.js b/npm/react/cypress/component/advanced/mock-fetch/fetch.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mock-fetch/fetch-spec.js rename to npm/react/cypress/component/advanced/mock-fetch/fetch.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-axios/1-users.spec.js b/npm/react/cypress/component/advanced/mocking-axios/1-users.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-axios/1-users.spec.js rename to npm/react/cypress/component/advanced/mocking-axios/1-users.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-axios/2-users-named.spec.js b/npm/react/cypress/component/advanced/mocking-axios/2-users-named.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-axios/2-users-named.spec.js rename to npm/react/cypress/component/advanced/mocking-axios/2-users-named.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-axios/3-users-api.spec.js b/npm/react/cypress/component/advanced/mocking-axios/3-users-api.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-axios/3-users-api.spec.js rename to npm/react/cypress/component/advanced/mocking-axios/3-users-api.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-component/spec.js b/npm/react/cypress/component/advanced/mocking-component/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-component/spec.js rename to npm/react/cypress/component/advanced/mocking-component/spec.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-imports/PizzaProps.spec.js b/npm/react/cypress/component/advanced/mocking-imports/PizzaProps.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-imports/PizzaProps.spec.js rename to npm/react/cypress/component/advanced/mocking-imports/PizzaProps.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-imports/RemotePizza.spec.js b/npm/react/cypress/component/advanced/mocking-imports/RemotePizza.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-imports/RemotePizza.spec.js rename to npm/react/cypress/component/advanced/mocking-imports/RemotePizza.cy.js diff --git a/npm/react/cypress/component/advanced/mocking-imports/spec.js b/npm/react/cypress/component/advanced/mocking-imports/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/mocking-imports/spec.js rename to npm/react/cypress/component/advanced/mocking-imports/spec.cy.js diff --git a/npm/react/cypress/component/advanced/portal/portal-spec.js b/npm/react/cypress/component/advanced/portal/portal.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/portal/portal-spec.js rename to npm/react/cypress/component/advanced/portal/portal.cy.js diff --git a/npm/react/cypress/component/advanced/radioactive-state/counter/counter-spec.js b/npm/react/cypress/component/advanced/radioactive-state/counter/counter.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/radioactive-state/counter/counter-spec.js rename to npm/react/cypress/component/advanced/radioactive-state/counter/counter.cy.js diff --git a/npm/react/cypress/component/advanced/radioactive-state/counters/counters-spec.js b/npm/react/cypress/component/advanced/radioactive-state/counters/counters.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/radioactive-state/counters/counters-spec.js rename to npm/react/cypress/component/advanced/radioactive-state/counters/counters.cy.js diff --git a/npm/react/cypress/component/advanced/radioactive-state/todos/todos-spec.js b/npm/react/cypress/component/advanced/radioactive-state/todos/todos.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/radioactive-state/todos/todos-spec.js rename to npm/react/cypress/component/advanced/radioactive-state/todos/todos.cy.js diff --git a/npm/react/cypress/component/advanced/react-book-example/src/Note.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/Note.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-book-example/src/Note.spec.js rename to npm/react/cypress/component/advanced/react-book-example/src/Note.cy.js diff --git a/npm/react/cypress/component/advanced/react-book-example/src/Todos.cy.js b/npm/react/cypress/component/advanced/react-book-example/src/Todos.cy.js new file mode 100644 index 0000000000..b12cec5f53 --- /dev/null +++ b/npm/react/cypress/component/advanced/react-book-example/src/Todos.cy.js @@ -0,0 +1,49 @@ +/// +import { mount } from '@cypress/react' +import React from 'react' +import Todos from './Todos' +import pretty from 'pretty' +import { stripIndent } from 'common-tags' + +it('Todo - should create snapshot', () => { + cy.viewport(400, 400) + mount( + , + ) + + cy.get('[data-testid=item]').should('have.length', 2) + // disabled snapshot commands for now + // to speed up bundling + // let tree = component.toJSON(); + // expect(tree).toMatchSnapshot(); + + // entire test area + cy.get('[data-cy-root]') + .invoke('html') + .then(pretty) + .should( + 'equal', + stripIndent` +

item1

+
an item
+

item2

+
another item
+ `, + ) + + cy.contains('[data-testid=item]', 'item1').should('be.visible') + // selecting works + cy.contains('[data-testid=item]', 'item2') + .next() + .should('have.text', 'another item') + .next() + .should('have.text', 'Select') + .click() + + cy.contains('[data-testid=item]', 'item2').should('have.class', 'selected') +}) diff --git a/npm/react/cypress/component/advanced/react-book-example/src/Todos.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/Todos.spec.js deleted file mode 100644 index 5473fb01cc..0000000000 --- a/npm/react/cypress/component/advanced/react-book-example/src/Todos.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -/// -import { mount } from '@cypress/react' -import React from 'react' -import Todos from './Todos' -import pretty from 'pretty' -import { stripIndent } from 'common-tags' - -it('Todo - should create snapshot', () => { - cy.viewport(400, 400) - mount( - , - ) - - cy.get('[data-testid=item]').should('have.length', 2) - // disabled snapshot commands for now - // to speed up bundling - // let tree = component.toJSON(); - // expect(tree).toMatchSnapshot(); - - // entire test area - cy.get('#__cy_root') - .invoke('html') - .then(pretty) - .should( - 'equal', - stripIndent` -

item1

-
an item
-

item2

-
another item
- `, - ) - - cy.contains('[data-testid=item]', 'item1').should('be.visible') - // selecting works - cy.contains('[data-testid=item]', 'item2') - .next() - .should('have.text', 'another item') - .next() - .should('have.text', 'Select') - .click() - - cy.contains('[data-testid=item]', 'item2').should('have.class', 'selected') -}) diff --git a/npm/react/cypress/component/advanced/react-book-example/src/add.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/add.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-book-example/src/add.spec.js rename to npm/react/cypress/component/advanced/react-book-example/src/add.cy.js diff --git a/npm/react/cypress/component/advanced/react-book-example/src/add2.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/add2.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-book-example/src/add2.spec.js rename to npm/react/cypress/component/advanced/react-book-example/src/add2.cy.js diff --git a/npm/react/cypress/component/advanced/react-book-example/src/components/ProductsList.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/components/ProductsList.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-book-example/src/components/ProductsList.spec.js rename to npm/react/cypress/component/advanced/react-book-example/src/components/ProductsList.cy.js diff --git a/npm/react/cypress/component/advanced/react-book-example/src/products.spec.js b/npm/react/cypress/component/advanced/react-book-example/src/products.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-book-example/src/products.spec.js rename to npm/react/cypress/component/advanced/react-book-example/src/products.cy.js diff --git a/npm/react/cypress/component/advanced/react-bootstrap/dropdown-spec.js b/npm/react/cypress/component/advanced/react-bootstrap/dropdown.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-bootstrap/dropdown-spec.js rename to npm/react/cypress/component/advanced/react-bootstrap/dropdown.cy.js diff --git a/npm/react/cypress/component/advanced/react-bootstrap/modal-spec.js b/npm/react/cypress/component/advanced/react-bootstrap/modal.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-bootstrap/modal-spec.js rename to npm/react/cypress/component/advanced/react-bootstrap/modal.cy.js diff --git a/npm/react/cypress/component/advanced/react-router-v6/in-memory-spec.js b/npm/react/cypress/component/advanced/react-router-v6/in-memory-spec.js deleted file mode 100644 index 5615dd9cd4..0000000000 --- a/npm/react/cypress/component/advanced/react-router-v6/in-memory-spec.js +++ /dev/null @@ -1,42 +0,0 @@ -/// -import React from 'react' -import { mount } from '@cypress/react' -import { App } from './app.jsx' -import { MemoryRouter } from 'react-router-dom' - -describe('React Memory Router', () => { - it('navigates through the link without changing url', () => { - cy.viewport(600, 300) - mount( - - - , - ) - - // we are mocking the initial open route with `initialIndex` - // so we should see "About" component - cy.log('**About** component') - cy.contains('h2', 'About') - // because the routing is in memory, the URL stays at the spec filename - cy.location('pathname').should('match', /in-memory-spec.js$/) - - // Go to home route - cy.contains('a', 'Home').click() - - cy.log('**Home** component') - cy.contains('h2', 'Home') // from the "Home" component - // still at the spec url - cy.location('pathname').should('match', /in-memory-spec.js$/) - - // Go to about route - cy.log('back to **About** component') - cy.contains('a', 'About').click() - - cy.contains('h2', 'About') - // still at the spec url - cy.location('pathname').should('match', /in-memory-spec.js$/) - }) -}) diff --git a/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.js b/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.js new file mode 100644 index 0000000000..0720c6cc93 --- /dev/null +++ b/npm/react/cypress/component/advanced/react-router-v6/in-memory.cy.js @@ -0,0 +1,42 @@ +/// +import React from 'react' +import { mount } from '@cypress/react' +import { App } from './app.jsx' +import { MemoryRouter } from 'react-router-dom' + +describe('React Memory Router', () => { + it('navigates through the link without changing url', () => { + cy.viewport(600, 300) + mount( + + + , + ) + + // we are mocking the initial open route with `initialIndex` + // so we should see "About" component + cy.log('**About** component') + cy.contains('h2', 'About') + // because the routing is in memory, the URL stays at the spec filename + cy.location('pathname').should('match', /in-memory.cy.js$/) + + // Go to home route + cy.contains('a', 'Home').click() + + cy.log('**Home** component') + cy.contains('h2', 'Home') // from the "Home" component + // still at the spec url + cy.location('pathname').should('match', /in-memory.cy.js$/) + + // Go to about route + cy.log('back to **About** component') + cy.contains('a', 'About').click() + + cy.contains('h2', 'About') + // still at the spec url + cy.location('pathname').should('match', /in-memory.cy.js$/) + }) +}) diff --git a/npm/react/cypress/component/advanced/react-router-v6/spec.js b/npm/react/cypress/component/advanced/react-router-v6/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/react-router-v6/spec.js rename to npm/react/cypress/component/advanced/react-router-v6/spec.cy.js diff --git a/npm/react/cypress/component/advanced/renderless/mouse-spec.js b/npm/react/cypress/component/advanced/renderless/mouse-spec.js deleted file mode 100644 index 8cf8aa87b8..0000000000 --- a/npm/react/cypress/component/advanced/renderless/mouse-spec.js +++ /dev/null @@ -1,48 +0,0 @@ -/// -import React from 'react' -import { mount, unmount } from '@cypress/react' -import MouseMovement from './mouse-movement' - -describe('Renderless component', () => { - it('works', () => { - // let's also spy on "console.log" calls - // to make sure the entire sequence of calls happens - cy.window() - .its('console') - .then((console) => { - cy.spy(console, 'log').as('log') - }) - - const onMoved = cy.stub() - - mount() - cy.get('#__cy_root').should('be.empty') - cy.document() - .trigger('mousemove') - .then(() => { - expect(onMoved).to.have.been.calledWith(true) - }) - - unmount() - - cy.get('@log') - .its('callCount') - .should('equal', 4) - - cy.get('@log') - .invoke('getCalls') - .then((calls) => { - return calls.map((call) => { - console.log('one', call.args[0]) - - return call.args[0] - }) - }) - .should('deep.equal', [ - 'MouseMovement constructor', - 'MouseMovement componentWillMount', - 'MouseMovement onMouseMove', - 'MouseMovement componentWillUnmount', - ]) - }) -}) diff --git a/npm/react/cypress/component/advanced/renderless/mouse.cy.js b/npm/react/cypress/component/advanced/renderless/mouse.cy.js new file mode 100644 index 0000000000..027317cdb1 --- /dev/null +++ b/npm/react/cypress/component/advanced/renderless/mouse.cy.js @@ -0,0 +1,48 @@ +/// +import React from 'react' +import { mount, unmount } from '@cypress/react' +import MouseMovement from './mouse-movement' + +describe('Renderless component', () => { + it('works', () => { + // let's also spy on "console.log" calls + // to make sure the entire sequence of calls happens + cy.window() + .its('console') + .then((console) => { + cy.spy(console, 'log').as('log') + }) + + const onMoved = cy.stub() + + mount() + cy.get('[data-cy-root]').should('be.empty') + cy.document() + .trigger('mousemove') + .then(() => { + expect(onMoved).to.have.been.calledWith(true) + }) + + unmount() + + cy.get('@log') + .its('callCount') + .should('equal', 4) + + cy.get('@log') + .invoke('getCalls') + .then((calls) => { + return calls.map((call) => { + console.log('one', call.args[0]) + + return call.args[0] + }) + }) + .should('deep.equal', [ + 'MouseMovement constructor', + 'MouseMovement componentWillMount', + 'MouseMovement onMouseMove', + 'MouseMovement componentWillUnmount', + ]) + }) +}) diff --git a/npm/react/cypress/component/advanced/set-timeout-example/app-spec.js b/npm/react/cypress/component/advanced/set-timeout-example/app.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/set-timeout-example/app-spec.js rename to npm/react/cypress/component/advanced/set-timeout-example/app.cy.js diff --git a/npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js b/npm/react/cypress/component/advanced/set-timeout-example/loading-indicator.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js rename to npm/react/cypress/component/advanced/set-timeout-example/loading-indicator.cy.js diff --git a/npm/react/cypress/component/advanced/test-retries/spec.js b/npm/react/cypress/component/advanced/test-retries/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/test-retries/spec.js rename to npm/react/cypress/component/advanced/test-retries/spec.cy.js diff --git a/npm/react/cypress/component/advanced/testing-lib-example/spec.js b/npm/react/cypress/component/advanced/testing-lib-example/spec.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/testing-lib-example/spec.js rename to npm/react/cypress/component/advanced/testing-lib-example/spec.cy.js diff --git a/npm/react/cypress/component/advanced/testing-lib-example/testing-lib-spec.js b/npm/react/cypress/component/advanced/testing-lib-example/testing-lib.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/testing-lib-example/testing-lib-spec.js rename to npm/react/cypress/component/advanced/testing-lib-example/testing-lib.cy.js diff --git a/npm/react/cypress/component/advanced/timers/card-without-effect-spec.js b/npm/react/cypress/component/advanced/timers/card-without-effect.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/timers/card-without-effect-spec.js rename to npm/react/cypress/component/advanced/timers/card-without-effect.cy.js diff --git a/npm/react/cypress/component/advanced/timers/card-spec.js b/npm/react/cypress/component/advanced/timers/card.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/timers/card-spec.js rename to npm/react/cypress/component/advanced/timers/card.cy.js diff --git a/npm/react/cypress/component/advanced/tutorial/shopping-list-spec.js b/npm/react/cypress/component/advanced/tutorial/shopping-list.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/tutorial/shopping-list-spec.js rename to npm/react/cypress/component/advanced/tutorial/shopping-list.cy.js diff --git a/npm/react/cypress/component/advanced/tutorial/square-spec.js b/npm/react/cypress/component/advanced/tutorial/square.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/tutorial/square-spec.js rename to npm/react/cypress/component/advanced/tutorial/square.cy.js diff --git a/npm/react/cypress/component/advanced/tutorial/tic-tac-toe-spec.js b/npm/react/cypress/component/advanced/tutorial/tic-tac-toe.cy.js similarity index 100% rename from npm/react/cypress/component/advanced/tutorial/tic-tac-toe-spec.js rename to npm/react/cypress/component/advanced/tutorial/tic-tac-toe.cy.js diff --git a/npm/react/cypress/component/advanced/use-local-storage/App.spec.jsx b/npm/react/cypress/component/advanced/use-local-storage/App.cy.jsx similarity index 100% rename from npm/react/cypress/component/advanced/use-local-storage/App.spec.jsx rename to npm/react/cypress/component/advanced/use-local-storage/App.cy.jsx diff --git a/npm/react/cypress/component/basic/alert-spec.js b/npm/react/cypress/component/basic/alert.cy.js similarity index 100% rename from npm/react/cypress/component/basic/alert-spec.js rename to npm/react/cypress/component/basic/alert.cy.js diff --git a/npm/react/cypress/component/basic/alias/alias-spec.js b/npm/react/cypress/component/basic/alias/alias.cy.js similarity index 100% rename from npm/react/cypress/component/basic/alias/alias-spec.js rename to npm/react/cypress/component/basic/alias/alias.cy.js diff --git a/npm/react/cypress/component/basic/before-hook/spec.js b/npm/react/cypress/component/basic/before-hook/spec.cy.js similarity index 100% rename from npm/react/cypress/component/basic/before-hook/spec.js rename to npm/react/cypress/component/basic/before-hook/spec.cy.js diff --git a/npm/react/cypress/component/basic/counter-set-state/counter-spec.js b/npm/react/cypress/component/basic/counter-set-state/counter.cy.js similarity index 100% rename from npm/react/cypress/component/basic/counter-set-state/counter-spec.js rename to npm/react/cypress/component/basic/counter-set-state/counter.cy.js diff --git a/npm/react/cypress/component/basic/counter-use-hooks/counter-hooks-spec.js b/npm/react/cypress/component/basic/counter-use-hooks/counter-hooks.cy.js similarity index 100% rename from npm/react/cypress/component/basic/counter-use-hooks/counter-hooks-spec.js rename to npm/react/cypress/component/basic/counter-use-hooks/counter-hooks.cy.js diff --git a/npm/react/cypress/component/basic/css-modules/css-modules-orange-button-spec.js b/npm/react/cypress/component/basic/css-modules/css-modules-orange-button.cy.js similarity index 100% rename from npm/react/cypress/component/basic/css-modules/css-modules-orange-button-spec.js rename to npm/react/cypress/component/basic/css-modules/css-modules-orange-button.cy.js diff --git a/npm/react/cypress/component/basic/css/css-orange-button-spec.js b/npm/react/cypress/component/basic/css/css-orange-button.cy.js similarity index 100% rename from npm/react/cypress/component/basic/css/css-orange-button-spec.js rename to npm/react/cypress/component/basic/css/css-orange-button.cy.js diff --git a/npm/react/cypress/component/basic/document/document-spec.js b/npm/react/cypress/component/basic/document/document.cy.js similarity index 100% rename from npm/react/cypress/component/basic/document/document-spec.js rename to npm/react/cypress/component/basic/document/document.cy.js diff --git a/npm/react/cypress/component/basic/emotion-spec.js b/npm/react/cypress/component/basic/emotion.cy.js similarity index 100% rename from npm/react/cypress/component/basic/emotion-spec.js rename to npm/react/cypress/component/basic/emotion.cy.js diff --git a/npm/react/cypress/component/basic/enzyme/context-spec.js b/npm/react/cypress/component/basic/enzyme/context.cy.js similarity index 100% rename from npm/react/cypress/component/basic/enzyme/context-spec.js rename to npm/react/cypress/component/basic/enzyme/context.cy.js diff --git a/npm/react/cypress/component/basic/enzyme/props-spec.js b/npm/react/cypress/component/basic/enzyme/props.cy.js similarity index 100% rename from npm/react/cypress/component/basic/enzyme/props-spec.js rename to npm/react/cypress/component/basic/enzyme/props.cy.js diff --git a/npm/react/cypress/component/basic/enzyme/state-spec.js b/npm/react/cypress/component/basic/enzyme/state.cy.js similarity index 100% rename from npm/react/cypress/component/basic/enzyme/state-spec.js rename to npm/react/cypress/component/basic/enzyme/state.cy.js diff --git a/npm/react/cypress/component/basic/error-boundary-spec.js b/npm/react/cypress/component/basic/error-boundary.cy.js similarity index 100% rename from npm/react/cypress/component/basic/error-boundary-spec.js rename to npm/react/cypress/component/basic/error-boundary.cy.js diff --git a/npm/react/cypress/component/basic/fails-correctly/spec.js b/npm/react/cypress/component/basic/fails-correctly/spec.cy.js similarity index 100% rename from npm/react/cypress/component/basic/fails-correctly/spec.js rename to npm/react/cypress/component/basic/fails-correctly/spec.cy.js diff --git a/npm/react/cypress/component/basic/full-navigation-spec.js b/npm/react/cypress/component/basic/full-navigation.cy.js similarity index 100% rename from npm/react/cypress/component/basic/full-navigation-spec.js rename to npm/react/cypress/component/basic/full-navigation.cy.js diff --git a/npm/react/cypress/component/basic/hello-act-spec.js b/npm/react/cypress/component/basic/hello-act.cy.js similarity index 100% rename from npm/react/cypress/component/basic/hello-act-spec.js rename to npm/react/cypress/component/basic/hello-act.cy.js diff --git a/npm/react/cypress/component/basic/hello-world-inline-spec.js b/npm/react/cypress/component/basic/hello-world-inline.cy.js similarity index 100% rename from npm/react/cypress/component/basic/hello-world-inline-spec.js rename to npm/react/cypress/component/basic/hello-world-inline.cy.js diff --git a/npm/react/cypress/component/basic/hello-world-spec.js b/npm/react/cypress/component/basic/hello-world.cy.js similarity index 100% rename from npm/react/cypress/component/basic/hello-world-spec.js rename to npm/react/cypress/component/basic/hello-world.cy.js diff --git a/npm/react/cypress/component/basic/hello-x-spec.js b/npm/react/cypress/component/basic/hello-x.cy.js similarity index 100% rename from npm/react/cypress/component/basic/hello-x-spec.js rename to npm/react/cypress/component/basic/hello-x.cy.js diff --git a/npm/react/cypress/component/basic/mount-div/spec.js b/npm/react/cypress/component/basic/mount-div/spec.cy.js similarity index 100% rename from npm/react/cypress/component/basic/mount-div/spec.js rename to npm/react/cypress/component/basic/mount-div/spec.cy.js diff --git a/npm/react/cypress/component/basic/network/1-users-spec.js b/npm/react/cypress/component/basic/network/1-users.cy.js similarity index 100% rename from npm/react/cypress/component/basic/network/1-users-spec.js rename to npm/react/cypress/component/basic/network/1-users.cy.js diff --git a/npm/react/cypress/component/basic/network/2-users-fetch-spec.js b/npm/react/cypress/component/basic/network/2-users-fetch.cy.js similarity index 100% rename from npm/react/cypress/component/basic/network/2-users-fetch-spec.js rename to npm/react/cypress/component/basic/network/2-users-fetch.cy.js diff --git a/npm/react/cypress/component/basic/no-visit/spec.js b/npm/react/cypress/component/basic/no-visit/spec.cy.js similarity index 100% rename from npm/react/cypress/component/basic/no-visit/spec.js rename to npm/react/cypress/component/basic/no-visit/spec.cy.js diff --git a/npm/react/cypress/component/basic/pure-component.spec.js b/npm/react/cypress/component/basic/pure-component.cy.js similarity index 100% rename from npm/react/cypress/component/basic/pure-component.spec.js rename to npm/react/cypress/component/basic/pure-component.cy.js diff --git a/npm/react/cypress/component/basic/react-book-by-chris-noring/components-spec.js b/npm/react/cypress/component/basic/react-book-by-chris-noring/components.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-book-by-chris-noring/components-spec.js rename to npm/react/cypress/component/basic/react-book-by-chris-noring/components.cy.js diff --git a/npm/react/cypress/component/basic/react-book-by-chris-noring/jsx-spec.js b/npm/react/cypress/component/basic/react-book-by-chris-noring/jsx.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-book-by-chris-noring/jsx-spec.js rename to npm/react/cypress/component/basic/react-book-by-chris-noring/jsx.cy.js diff --git a/npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todo-spec.js b/npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todo.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todo-spec.js rename to npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todo.cy.js diff --git a/npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todos-spec.js b/npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todos.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todos-spec.js rename to npm/react/cypress/component/basic/react-book-by-chris-noring/thinking-in-components/Todos.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/game-spec.js b/npm/react/cypress/component/basic/react-tutorial/game.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/game-spec.js rename to npm/react/cypress/component/basic/react-tutorial/game.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/hello-spec.js b/npm/react/cypress/component/basic/react-tutorial/hello.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/hello-spec.js rename to npm/react/cypress/component/basic/react-tutorial/hello.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots-spec.js b/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots-spec.js deleted file mode 100644 index 6ca64034c2..0000000000 --- a/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots-spec.js +++ /dev/null @@ -1,14 +0,0 @@ -/// -import Hello from './hello.jsx' -import React from 'react' -import { mount } from '@cypress/react' -import pretty from 'pretty' - -it('says hello world', () => { - mount() - cy.contains('Hello, world!').should('be.visible') - cy.get('#__cy_root') - .invoke('html') - .then(pretty) - .should('equal', '

Hello, world!

') -}) diff --git a/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots.cy.js b/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots.cy.js new file mode 100644 index 0000000000..fa4f9a8fdb --- /dev/null +++ b/npm/react/cypress/component/basic/react-tutorial/pretty-snapshots.cy.js @@ -0,0 +1,14 @@ +/// +import Hello from './hello.jsx' +import React from 'react' +import { mount } from '@cypress/react' +import pretty from 'pretty' + +it('says hello world', () => { + mount() + cy.contains('Hello, world!').should('be.visible') + cy.get('[data-cy-root]') + .invoke('html') + .then(pretty) + .should('equal', '

Hello, world!

') +}) diff --git a/npm/react/cypress/component/basic/react-tutorial/shopping-list-spec.js b/npm/react/cypress/component/basic/react-tutorial/shopping-list.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/shopping-list-spec.js rename to npm/react/cypress/component/basic/react-tutorial/shopping-list.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/square1-spec.js b/npm/react/cypress/component/basic/react-tutorial/square1.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/square1-spec.js rename to npm/react/cypress/component/basic/react-tutorial/square1.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/square2-spec.js b/npm/react/cypress/component/basic/react-tutorial/square2.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/square2-spec.js rename to npm/react/cypress/component/basic/react-tutorial/square2.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/square3-spec.js b/npm/react/cypress/component/basic/react-tutorial/square3.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/square3-spec.js rename to npm/react/cypress/component/basic/react-tutorial/square3.cy.js diff --git a/npm/react/cypress/component/basic/react-tutorial/square4-spec.js b/npm/react/cypress/component/basic/react-tutorial/square4.cy.js similarity index 100% rename from npm/react/cypress/component/basic/react-tutorial/square4-spec.js rename to npm/react/cypress/component/basic/react-tutorial/square4.cy.js diff --git a/npm/react/cypress/component/basic/rerender/different-element.spec.jsx b/npm/react/cypress/component/basic/rerender/different-element.cy.jsx similarity index 100% rename from npm/react/cypress/component/basic/rerender/different-element.spec.jsx rename to npm/react/cypress/component/basic/rerender/different-element.cy.jsx diff --git a/npm/react/cypress/component/basic/rerender/effects.spec.jsx b/npm/react/cypress/component/basic/rerender/effects.cy.jsx similarity index 100% rename from npm/react/cypress/component/basic/rerender/effects.spec.jsx rename to npm/react/cypress/component/basic/rerender/effects.cy.jsx diff --git a/npm/react/cypress/component/basic/rerender/input-accumulator.spec.jsx b/npm/react/cypress/component/basic/rerender/input-accumulator.cy.jsx similarity index 100% rename from npm/react/cypress/component/basic/rerender/input-accumulator.spec.jsx rename to npm/react/cypress/component/basic/rerender/input-accumulator.cy.jsx diff --git a/npm/react/cypress/component/basic/stateless-spec.js b/npm/react/cypress/component/basic/stateless.cy.js similarity index 100% rename from npm/react/cypress/component/basic/stateless-spec.js rename to npm/react/cypress/component/basic/stateless.cy.js diff --git a/npm/react/cypress/component/basic/stub-example/clicker-with-delay-spec.js b/npm/react/cypress/component/basic/stub-example/clicker-with-delay.cy.js similarity index 100% rename from npm/react/cypress/component/basic/stub-example/clicker-with-delay-spec.js rename to npm/react/cypress/component/basic/stub-example/clicker-with-delay.cy.js diff --git a/npm/react/cypress/component/basic/stub-example/clicker-spec.js b/npm/react/cypress/component/basic/stub-example/clicker.cy.js similarity index 100% rename from npm/react/cypress/component/basic/stub-example/clicker-spec.js rename to npm/react/cypress/component/basic/stub-example/clicker.cy.js diff --git a/npm/react/cypress/component/basic/styled-components/Todo-spec.js b/npm/react/cypress/component/basic/styled-components/Todo.cy.js similarity index 100% rename from npm/react/cypress/component/basic/styled-components/Todo-spec.js rename to npm/react/cypress/component/basic/styled-components/Todo.cy.js diff --git a/npm/react/cypress/component/basic/styled-components/Todos-spec.js b/npm/react/cypress/component/basic/styled-components/Todos.cy.js similarity index 100% rename from npm/react/cypress/component/basic/styled-components/Todos-spec.js rename to npm/react/cypress/component/basic/styled-components/Todos.cy.js diff --git a/npm/react/cypress/component/basic/styled-components/issue-15879.spec.js b/npm/react/cypress/component/basic/styled-components/issue-15879.cy.js similarity index 100% rename from npm/react/cypress/component/basic/styled-components/issue-15879.spec.js rename to npm/react/cypress/component/basic/styled-components/issue-15879.cy.js diff --git a/npm/react/cypress/component/basic/styles/style/style-spec.js b/npm/react/cypress/component/basic/styles/style/style.cy.js similarity index 100% rename from npm/react/cypress/component/basic/styles/style/style-spec.js rename to npm/react/cypress/component/basic/styles/style/style.cy.js diff --git a/npm/react/cypress/component/basic/toggle-example/toggle-spec.js b/npm/react/cypress/component/basic/toggle-example/toggle.cy.js similarity index 100% rename from npm/react/cypress/component/basic/toggle-example/toggle-spec.js rename to npm/react/cypress/component/basic/toggle-example/toggle.cy.js diff --git a/npm/react/cypress/component/basic/transpiled-spec.js b/npm/react/cypress/component/basic/transpiled.cy.js similarity index 100% rename from npm/react/cypress/component/basic/transpiled-spec.js rename to npm/react/cypress/component/basic/transpiled.cy.js diff --git a/npm/react/cypress/component/basic/typescript/ts-spec.tsx b/npm/react/cypress/component/basic/typescript/ts-spec.cy.tsx similarity index 100% rename from npm/react/cypress/component/basic/typescript/ts-spec.tsx rename to npm/react/cypress/component/basic/typescript/ts-spec.cy.tsx diff --git a/npm/react/cypress/component/basic/unmount/comp-spec.js b/npm/react/cypress/component/basic/unmount/comp.cy.js similarity index 100% rename from npm/react/cypress/component/basic/unmount/comp-spec.js rename to npm/react/cypress/component/basic/unmount/comp.cy.js diff --git a/npm/react/cypress/component/basic/unmount/unmount-spec.js b/npm/react/cypress/component/basic/unmount/unmount.cy.js similarity index 100% rename from npm/react/cypress/component/basic/unmount/unmount-spec.js rename to npm/react/cypress/component/basic/unmount/unmount.cy.js diff --git a/npm/react/cypress/component/basic/use-lodash-fp/lodash-fp-spec.js b/npm/react/cypress/component/basic/use-lodash-fp/lodash-fp.cy.js similarity index 100% rename from npm/react/cypress/component/basic/use-lodash-fp/lodash-fp-spec.js rename to npm/react/cypress/component/basic/use-lodash-fp/lodash-fp.cy.js diff --git a/npm/react/cypress/component/basic/use-render/my-component-spec.js b/npm/react/cypress/component/basic/use-render/my-component.cy.js similarity index 100% rename from npm/react/cypress/component/basic/use-render/my-component-spec.js rename to npm/react/cypress/component/basic/use-render/my-component.cy.js diff --git a/npm/react/cypress/component/basic/window-spec.js b/npm/react/cypress/component/basic/window-spec.js deleted file mode 100644 index 3d25d677f6..0000000000 --- a/npm/react/cypress/component/basic/window-spec.js +++ /dev/null @@ -1,36 +0,0 @@ -/// -import React from 'react' -import { mount } from '@cypress/react' - -export class Component extends React.Component { - constructor (props) { - super(props) - console.log( - 'set window.counter to this component in window', - window.location.pathname, - ) - - window.component = this - } - - render () { - return

component

- } -} - -it('has the same window from the component as from test', () => { - cy.window() - .its('location') - .should('have.property', 'pathname') - .and('not.equal', 'blank') - - mount() - cy.contains('component') - cy.window() - .its('location.pathname') - // this filename - .should('match', /window-spec\.js$/) - - // the window should have property set by the component - cy.window().should('have.property', 'component') -}) diff --git a/npm/react/cypress/component/basic/window.cy.js b/npm/react/cypress/component/basic/window.cy.js new file mode 100644 index 0000000000..5450a96d18 --- /dev/null +++ b/npm/react/cypress/component/basic/window.cy.js @@ -0,0 +1,36 @@ +/// +import React from 'react' +import { mount } from '@cypress/react' + +export class Component extends React.Component { + constructor (props) { + super(props) + console.log( + 'set window.counter to this component in window', + window.location.pathname, + ) + + window.component = this + } + + render () { + return

component

+ } +} + +it('has the same window from the component as from test', () => { + cy.window() + .its('location') + .should('have.property', 'pathname') + .and('not.equal', 'blank') + + mount() + cy.contains('component') + cy.window() + .its('location.pathname') + // this filename + .should('match', /window.cy.js$/) + + // the window should have property set by the component + cy.window().should('have.property', 'component') +}) diff --git a/npm/react/cypress/component/basic/wrap-spec.js b/npm/react/cypress/component/basic/wrap.cy.js similarity index 100% rename from npm/react/cypress/component/basic/wrap-spec.js rename to npm/react/cypress/component/basic/wrap.cy.js diff --git a/npm/react/cypress/component/smoke-spec.js b/npm/react/cypress/component/smoke.cy.js similarity index 100% rename from npm/react/cypress/component/smoke-spec.js rename to npm/react/cypress/component/smoke.cy.js diff --git a/npm/react/cypress/component/viewport-spec.jsx b/npm/react/cypress/component/viewport-spec.jsx deleted file mode 100644 index 74ac9ec72c..0000000000 --- a/npm/react/cypress/component/viewport-spec.jsx +++ /dev/null @@ -1,23 +0,0 @@ -const viewportWidth = 200 -const viewportHeight = 100 - -describe('cypress.json viewport', - { viewportWidth, viewportHeight }, - () => { - it('should have the correct dimensions', () => { - // cy.should cannot be the first cy command we run - cy.window().should((w) => { - expect(w.innerWidth).to.eq(viewportWidth) - expect(w.innerHeight).to.eq(viewportHeight) - }) - }) - }) - -describe('cy.viewport', () => { - it('should resize the viewport', () => { - cy.viewport(viewportWidth, viewportHeight).should(() => { - expect(window.innerWidth).to.eq(viewportWidth) - expect(window.innerHeight).to.eq(viewportHeight) - }) - }) -}) diff --git a/npm/react/cypress/component/viewport.cy.jsx b/npm/react/cypress/component/viewport.cy.jsx new file mode 100644 index 0000000000..94353f5647 --- /dev/null +++ b/npm/react/cypress/component/viewport.cy.jsx @@ -0,0 +1,23 @@ +const viewportWidth = 200 +const viewportHeight = 100 + +describe('cypress.config.{ts|js} viewport', + { viewportWidth, viewportHeight }, + () => { + it('should have the correct dimensions', () => { + // cy.should cannot be the first cy command we run + cy.window().should((w) => { + expect(w.innerWidth).to.eq(viewportWidth) + expect(w.innerHeight).to.eq(viewportHeight) + }) + }) + }) + +describe('cy.viewport', () => { + it('should resize the viewport', () => { + cy.viewport(viewportWidth, viewportHeight).should(() => { + expect(window.innerWidth).to.eq(viewportWidth) + expect(window.innerHeight).to.eq(viewportHeight) + }) + }) +}) diff --git a/npm/react/cypress/integration/integration tests/integration-spec.js b/npm/react/cypress/e2e/integration tests/integration.cy.js similarity index 100% rename from npm/react/cypress/integration/integration tests/integration-spec.js rename to npm/react/cypress/e2e/integration tests/integration.cy.js diff --git a/npm/react/cypress/plugins/index.js b/npm/react/cypress/plugins/index.js deleted file mode 100644 index 036b2a068a..0000000000 --- a/npm/react/cypress/plugins/index.js +++ /dev/null @@ -1,73 +0,0 @@ -// @ts-check -const { startDevServer } = require('@cypress/webpack-dev-server') -const path = require('path') -const babelConfig = require('../../babel.config.js') - -/** @type import("webpack").Configuration */ -const webpackConfig = { - resolve: { - extensions: ['.js', '.ts', '.jsx', '.tsx'], - }, - mode: 'development', - devtool: false, - output: { - publicPath: '/', - chunkFilename: '[name].bundle.js', - }, - module: { - rules: [ - { - test: /\.(js|jsx|mjs|ts|tsx)$/, - loader: 'babel-loader', - options: { ...babelConfig, cacheDirectory: path.resolve(__dirname, '..', '..', '.babel-cache') }, - }, - { - test: /\.modules\.css$/i, - exclude: [/node_modules/], - use: [ - 'style-loader', - { - loader: 'css-loader', - options: { - modules: true, - }, - }, - ], - }, - { - test: /\.css$/, - exclude: [/node_modules/, /\.modules\.css$/i], - use: ['style-loader', 'css-loader'], - }, - { - // some of our examples import SVG - test: /\.svg$/, - loader: 'svg-url-loader', - }, - { - // some of our examples import SVG - test: /\.svg$/, - loader: 'svg-url-loader', - }, - { - test: /\.(png|jpg)$/, - use: ['file-loader'], - }, - ], - }, -} - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - if (config.testingType !== 'component') { - throw Error(`This is a component testing project. testingType should be 'component'. Received ${config.testingType}`) - } - - on('dev-server:start', (options) => { - return startDevServer({ options, webpackConfig, disableLazyCompilation: false }) - }) - - return config -} diff --git a/npm/react/cypress/support/component-index.html b/npm/react/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/cypress/support/component.js b/npm/react/cypress/support/component.js new file mode 100644 index 0000000000..6d11786826 --- /dev/null +++ b/npm/react/cypress/support/component.js @@ -0,0 +1,14 @@ +// *********************************************************** +// This example support/component.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** diff --git a/npm/react/cypress/support/index.js b/npm/react/cypress/support/index.js deleted file mode 100644 index 71550f1819..0000000000 --- a/npm/react/cypress/support/index.js +++ /dev/null @@ -1,14 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** diff --git a/npm/react/examples/a11y/README.md b/npm/react/examples/a11y/README.md deleted file mode 100644 index 405893163a..0000000000 --- a/npm/react/examples/a11y/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# example: a11y - -> Testing component accessibility - -## Usage - -1. Make sure the root project has been built . - -```bash -# in the root of the project -npm install -npm run build -``` - -2. Run `npm install` in this folder to symlink the `@cypress/react` dependency. - -```bash -# in this folder -npm install -``` - -3. Start Cypress - -```bash -npm run cy:open -# or just run headless tests -npm test -``` - -## Example - -Testing components following the [React accessibility guide](https://reactjs.org/docs/accessibility.html) using [cypress-axe](https://github.com/avanslaars/cypress-axe) plugin. - -See the spec file [cypress/component/spec.js](cypress/component/spec.js). For example, an `` without a label is caught: - -```js -mount() -cy.checkA11y('input', { - runOnly: { - type: 'tag', - values: ['wcag2a'], - }, -}) -``` - -![Input without a label](images/missing-label.png) - -You can click on the error to see more details in the DevTools console - -![Error details](images/label-error.png) diff --git a/npm/react/examples/a11y/cypress.json b/npm/react/examples/a11y/cypress.json deleted file mode 100644 index 49b616efaf..0000000000 --- a/npm/react/examples/a11y/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/examples/a11y/cypress/component/spec.js b/npm/react/examples/a11y/cypress/component/spec.js deleted file mode 100644 index 036dab3509..0000000000 --- a/npm/react/examples/a11y/cypress/component/spec.js +++ /dev/null @@ -1,43 +0,0 @@ -/// -import React from 'react' -import { mount } from '@cypress/react' - -describe('Accessibility', () => { - before(() => { - // https://github.com/avanslaars/cypress-axe - cy.injectAxe() - }) - - // https://www.w3.org/WAI/standards-guidelines/aria/ - context('aria', () => { - // NOTE: skip a failing test on purpose - it.skip('catches missing aria-* label', () => { - mount() - cy.checkA11y('input', { - runOnly: { - type: 'tag', - values: ['wcag2a'], - }, - }) - }) - - it('passes', () => { - mount( - , - ) - - cy.checkA11y('input', { - runOnly: { - type: 'tag', - values: ['wcag2a'], - }, - }) - }) - }) -}) diff --git a/npm/react/examples/a11y/cypress/plugins/index.js b/npm/react/examples/a11y/cypress/plugins/index.js deleted file mode 100644 index c0ba349a76..0000000000 --- a/npm/react/examples/a11y/cypress/plugins/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/a11y/cypress/support/index.js b/npm/react/examples/a11y/cypress/support/index.js deleted file mode 100644 index bb9acd4e3a..0000000000 --- a/npm/react/examples/a11y/cypress/support/index.js +++ /dev/null @@ -1 +0,0 @@ -require('cypress-axe') diff --git a/npm/react/examples/a11y/images/label-error.png b/npm/react/examples/a11y/images/label-error.png deleted file mode 100644 index f461484882..0000000000 Binary files a/npm/react/examples/a11y/images/label-error.png and /dev/null differ diff --git a/npm/react/examples/a11y/images/missing-label.png b/npm/react/examples/a11y/images/missing-label.png deleted file mode 100644 index d48ab0ec8b..0000000000 Binary files a/npm/react/examples/a11y/images/missing-label.png and /dev/null differ diff --git a/npm/react/examples/a11y/package.json b/npm/react/examples/a11y/package.json deleted file mode 100644 index 6be802048f..0000000000 --- a/npm/react/examples/a11y/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "example-a11y", - "description": "Testing component accessibility", - "private": true, - "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" - }, - "devDependencies": { - "@cypress/react": "file:../../dist", - "cypress-axe": "0.8.1", - "mocha-junit-reporter": "^2.0.0", - "mocha-multi-reporters": "^1.5.1" - } -} diff --git a/npm/react/examples/a11y/yarn.lock b/npm/react/examples/a11y/yarn.lock deleted file mode 100644 index 356980da55..0000000000 --- a/npm/react/examples/a11y/yarn.lock +++ /dev/null @@ -1,101 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@cypress/react@file:../../dist": - version "0.0.0" - -"@oozcitak/dom@1.15.8": - version "1.15.8" - resolved "https://registry.yarnpkg.com/@oozcitak/dom/-/dom-1.15.8.tgz#0c0c7bb54cfdaadc07fd637913e706101721d15d" - integrity sha512-MoOnLBNsF+ok0HjpAvxYxR4piUhRDCEWK0ot3upwOOHYudJd30j6M+LNcE8RKpwfnclAX9T66nXXzkytd29XSw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/url" "1.0.4" - "@oozcitak/util" "8.3.8" - -"@oozcitak/infra@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@oozcitak/infra/-/infra-1.0.8.tgz#b0b089421f7d0f6878687608301fbaba837a7d17" - integrity sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg== - dependencies: - "@oozcitak/util" "8.3.8" - -"@oozcitak/url@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@oozcitak/url/-/url-1.0.4.tgz#ca8b1c876319cf5a648dfa1123600a6aa5cda6ba" - integrity sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - -"@oozcitak/util@8.3.8": - version "8.3.8" - resolved "https://registry.yarnpkg.com/@oozcitak/util/-/util-8.3.8.tgz#10f65fe1891fd8cde4957360835e78fd1936bfdd" - integrity sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ== - -"@types/node@14.6.2": - version "14.6.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f" - integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -cypress-axe@0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/cypress-axe/-/cypress-axe-0.8.1.tgz#ddb37dca6570c0642dda2388daf678e83b3e8d3f" - integrity sha512-hX48+r5n7Ns7CHkn601Ag0JiCG1vby5+g7QhlP8X+mkiVYpTLpXAPiiaKFj9QTTCdZSI5+0UqwIxA+ShTsr5tA== - -cypress-circleci-reporter@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cypress-circleci-reporter/-/cypress-circleci-reporter-0.2.0.tgz#a3e1571694f4e21649a6af4d508e68948d23622d" - integrity sha512-uhqcJwvtKJ7Bw3RHVBTqUH9GP2L6jq+qLp/+/Jh3/OSe5Af6H7RxIARhvawsvbPrg9lMWdW/jCezjeUcXrl9uA== - dependencies: - strip-ansi "^6.0.0" - xmlbuilder2 "^2.1.1" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -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= - -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" - -xmlbuilder2@^2.1.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/xmlbuilder2/-/xmlbuilder2-2.4.0.tgz#fb6c5171bef1bcb984c88cfef5210e17b7b841cd" - integrity sha512-KrOVUGD65xTQ7ZA+GMQGdBSpe1Ufu5ylCQSYVk6QostySDkxPmAQ0WWIu7dR3JjLfVbF22RFQX7KyrZ6VTLcQg== - dependencies: - "@oozcitak/dom" "1.15.8" - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - "@types/node" "14.6.2" - js-yaml "3.14.0" diff --git a/npm/react/examples/craco/cypress.config.js b/npm/react/examples/craco/cypress.config.js new file mode 100644 index 0000000000..ee7fa1b52c --- /dev/null +++ b/npm/react/examples/craco/cypress.config.js @@ -0,0 +1,12 @@ +module.exports = { + 'component': { + setupNodeEvents (on, config) { + const cracoConfig = require('./craco.config.js') + const devServer = require('@cypress/react/plugins/craco') + + devServer(on, config, cracoConfig) + + return config + }, + }, +} diff --git a/npm/react/examples/craco/cypress.json b/npm/react/examples/craco/cypress.json deleted file mode 100644 index 0b8d066648..0000000000 --- a/npm/react/examples/craco/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "component": { - "testFiles": "**/*.test.{js,ts,jsx,tsx}", - "componentFolder": "src" - } -} diff --git a/npm/react/examples/craco/cypress/plugins/index.js b/npm/react/examples/craco/cypress/plugins/index.js deleted file mode 100644 index b9079a412e..0000000000 --- a/npm/react/examples/craco/cypress/plugins/index.js +++ /dev/null @@ -1,13 +0,0 @@ -// @ts-check - -const cracoConfig = require('../../craco.config.js') -const devServer = require('@cypress/react/plugins/craco') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - devServer(on, config, cracoConfig) - - return config -} diff --git a/npm/react/examples/craco/cypress/support/component-index.html b/npm/react/examples/craco/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/craco/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/craco/cypress/support/component.js b/npm/react/examples/craco/cypress/support/component.js new file mode 100644 index 0000000000..5e450a7b1a --- /dev/null +++ b/npm/react/examples/craco/cypress/support/component.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/component.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/npm/react/examples/craco/cypress/support/index.js b/npm/react/examples/craco/cypress/support/index.js deleted file mode 100644 index d68db96df2..0000000000 --- a/npm/react/examples/craco/cypress/support/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/npm/react/examples/craco/package.json b/npm/react/examples/craco/package.json index 700d130d32..4896fda14f 100644 --- a/npm/react/examples/craco/package.json +++ b/npm/react/examples/craco/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct", + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component", "start": "craco start", "build": "craco build" }, diff --git a/npm/react/examples/find-webpack/README.md b/npm/react/examples/find-webpack/README.md index 585a1231c5..14ce00e470 100644 --- a/npm/react/examples/find-webpack/README.md +++ b/npm/react/examples/find-webpack/README.md @@ -27,15 +27,14 @@ Next, create a `cypress.json` with some basic configuration: ```json { "component": { - "testFiles": "**/*.test.{js,ts,jsx,tsx}", - "componentFolder": "src" + "specPattern": "src/**/*.test.{js,ts,jsx,tsx}" } } ``` -Here we are adding some Component Testing specific options, hence the `"component"` key. `"componentFolder"` is where all the components and tests are located, and `"testFiles"` is the pattern to search for test files. +Here we are adding some Component Testing specific options, hence the `"component"` key. `"specPattern"` is the pattern to search for test files. -The last thing we need to is tell Cypress to use `@cypress/webpack-dev-server` for component tests. Plugins are explained in detail in the [Cypress documentation](https://docs.cypress.io/guides/tooling/plugins-guide#Installing-plugins). By default plugins are loaded from `cypress/plugins/index.js`. Create that file and add: +The last thing we need to is tell Cypress to use `@cypress/webpack-dev-server` for component tests. Plugins are explained in detail in the [Cypress documentation](https://on.cypress.io/installing-plugins). By default plugins are loaded from `cypress/plugins/index.js`. Create that file and add: ```js const devServer = require("@cypress/react/plugins/react-scripts") @@ -66,12 +65,12 @@ it('renders learn react link', () => { }); ``` -Most tests will start with `mount` from `@cypress/react`. This is similar to `render` in Testing Library. Once you've mounted your component, you can use Cypress' extensive [query and assertion APIs](https://docs.cypress.io/api/table-of-contents) to ensure everything behaves correctly. This example asserts an anchor tag with the text "Learn React" is rendered. +Most tests will start with `mount` from `@cypress/react`. This is similar to `render` in Testing Library. Once you've mounted your component, you can use Cypress' extensive [query and assertion APIs](https://on.cypress.io/api) to ensure everything behaves correctly. This example asserts an anchor tag with the text "Learn React" is rendered. Open the component testing runner with: ```sh -yarn cypress open-ct +yarn cypress open --component ``` And select the spec to run. @@ -80,7 +79,7 @@ And select the spec to run. Try making a change - the tests will re-run instantly. You not only immediately know if the test passed or failed, but be able to visually inspect and debug any changes. -You can run all the specs with `yarn cypress run-ct`. This is useful for executing all the specs in a CI environment, or one last check before you commit and push your code! +You can run all the specs with `yarn cypress run --component`. This is useful for executing all the specs in a CI environment, or one last check before you commit and push your code! ## Discussion @@ -90,13 +89,13 @@ Cypress Component Testing is an alternative to a jsdom based testing environment - Visual. You can see exactly what is rendered. No more scrolling through a cryptic terminal log to figure out what is rendered or to debug - just open the devtools and browse the DOM. - Powered by Cypress - the most popular and reliable E2E testing tool out there. -It also doubles as a *design environment*. You can see the component as you develop it, and hot reload give you a near instance feedback loop. It can potentially take the place of not only your Jest based test infrastructure, but your Storybook based design infrastructure as well. +It also doubles as a *design environment*. You can see the component as you develop it, and hot reload give you a near instance feedback loop. It can potentially take the place of not only your Jest based test infrastructure, but your Storybook based design infrastructure as well. Cypress Component Testing is still in alpha but the product is quickly evolving and promises to change the landscape of Component Testing. ## Conclusion -Cypress Component Testing brings everything that is great about Cypress to Component Testing. Since the underlying adapters are built on libraries like Webpack, you don't need to throw away your entire test suite - incremental migration is more than possible. +Cypress Component Testing brings everything that is great about Cypress to Component Testing. Since the underlying adapters are built on libraries like Webpack, you don't need to throw away your entire test suite - incremental migration is more than possible. The visual aspect united testing and design in a single tool. My days of grepping a messy console output to figure out what the user will see are over - I can see exactly what the component will look like as my tests run. diff --git a/npm/react/examples/find-webpack/cypress.config.ts b/npm/react/examples/find-webpack/cypress.config.ts new file mode 100644 index 0000000000..d1f26df9ca --- /dev/null +++ b/npm/react/examples/find-webpack/cypress.config.ts @@ -0,0 +1,37 @@ +import { defineConfig } from 'cypress' +import { devServer } from '@cypress/webpack-dev-server' + +export default defineConfig({ + 'video': true, + 'projectId': 'jq5xpp', + 'component': { + devServer (cypressDevServerConfig) { + const findReactScriptsWebpackConfig = require('@cypress/react/plugins/react-scripts/findReactScriptsWebpackConfig') + const _ = require('lodash') + + const map = _.map([4, 8], (n) => n * 2) + + console.log(map) + const webpackConfig = findReactScriptsWebpackConfig(cypressDevServerConfig.config) + + const rules = webpackConfig.module.rules.find((rule) => !!rule.oneOf).oneOf + const babelRule = rules.find((rule) => typeof rule.loader === 'string' && /babel-loader/.test(rule.loader)) + + typeof babelRule.options !== 'string' && babelRule.options.plugins.push(require.resolve('babel-plugin-istanbul')) + + return devServer(cypressDevServerConfig, { webpackConfig }) + }, + setupNodeEvents (on, config) { + require('@cypress/code-coverage/task')(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, + 'env': { + 'cypress-react-selector': { + 'root': '[data-cy-root]', + }, + }, +}) diff --git a/npm/react/examples/find-webpack/cypress.json b/npm/react/examples/find-webpack/cypress.json deleted file mode 100644 index 03ad0d3676..0000000000 --- a/npm/react/examples/find-webpack/cypress.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "video": true, - "projectId": "jq5xpp", - "component": { - "testFiles": "**/*.spec.{js,ts,jsx,tsx}", - "componentFolder": "src" - }, - "env": { - "cypress-react-selector": { - "root": "#__cy_root" - } - } -} diff --git a/npm/react/examples/find-webpack/cypress/plugins/index.js b/npm/react/examples/find-webpack/cypress/plugins/index.js deleted file mode 100644 index 36ab077029..0000000000 --- a/npm/react/examples/find-webpack/cypress/plugins/index.js +++ /dev/null @@ -1,29 +0,0 @@ -// @ts-check - -const findReactScriptsWebpackConfig = require('@cypress/react/plugins/react-scripts/findReactScriptsWebpackConfig') -const { startDevServer } = require('@cypress/webpack-dev-server') -const _ = require('lodash') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - const map = _.map([4, 8], (n) => n * 2) - - console.log(map) - require('@cypress/code-coverage/task')(on, config) - const webpackConfig = findReactScriptsWebpackConfig(config) - - const rules = webpackConfig.module.rules.find((rule) => !!rule.oneOf).oneOf - const babelRule = rules.find((rule) => typeof rule.loader === 'string' && /babel-loader/.test(rule.loader)) - - typeof babelRule.options !== 'string' && babelRule.options.plugins.push(require.resolve('babel-plugin-istanbul')) - - on('dev-server:start', (options) => { - return startDevServer({ options, webpackConfig }) - }) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/find-webpack/cypress/support/component-index.html b/npm/react/examples/find-webpack/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/find-webpack/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/find-webpack/cypress/support/index.ts b/npm/react/examples/find-webpack/cypress/support/component.ts similarity index 100% rename from npm/react/examples/find-webpack/cypress/support/index.ts rename to npm/react/examples/find-webpack/cypress/support/component.ts diff --git a/npm/react/examples/find-webpack/package.json b/npm/react/examples/find-webpack/package.json index 3af098b491..3789d43223 100644 --- a/npm/react/examples/find-webpack/package.json +++ b/npm/react/examples/find-webpack/package.json @@ -3,8 +3,8 @@ "version": "1.0.0", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component" }, "dependencies": { "@types/react": "^17.0.0", diff --git a/npm/react/examples/find-webpack/src/App.spec.jsx b/npm/react/examples/find-webpack/src/App.cy.jsx similarity index 100% rename from npm/react/examples/find-webpack/src/App.spec.jsx rename to npm/react/examples/find-webpack/src/App.cy.jsx diff --git a/npm/react/examples/nextjs-webpack-5/cypress.config.js b/npm/react/examples/nextjs-webpack-5/cypress.config.js new file mode 100644 index 0000000000..88f23e8f7f --- /dev/null +++ b/npm/react/examples/nextjs-webpack-5/cypress.config.js @@ -0,0 +1,11 @@ +const { devServer } = require('@cypress/react/plugins/next') + +module.exports = { + 'video': false, + 'viewportWidth': 500, + 'viewportHeight': 800, + 'pluginsFile': 'cypress/plugins.js', + 'component': { + devServer, + }, +} diff --git a/npm/react/examples/nextjs-webpack-5/cypress.json b/npm/react/examples/nextjs-webpack-5/cypress.json deleted file mode 100644 index 18c2d6098b..0000000000 --- a/npm/react/examples/nextjs-webpack-5/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "testFiles": "**/*.spec.{js,jsx}", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "cypress/components", - "pluginsFile": "cypress/plugins.js" -} \ No newline at end of file diff --git a/npm/react/examples/nextjs-webpack-5/cypress/components/Search.spec.jsx b/npm/react/examples/nextjs-webpack-5/cypress/components/Search.cy.jsx similarity index 100% rename from npm/react/examples/nextjs-webpack-5/cypress/components/Search.spec.jsx rename to npm/react/examples/nextjs-webpack-5/cypress/components/Search.cy.jsx diff --git a/npm/react/examples/nextjs-webpack-5/cypress/plugins.js b/npm/react/examples/nextjs-webpack-5/cypress/plugins.js deleted file mode 100644 index 3edcd42978..0000000000 --- a/npm/react/examples/nextjs-webpack-5/cypress/plugins.js +++ /dev/null @@ -1,10 +0,0 @@ -const devServer = require('@cypress/react/plugins/next') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - return config -} diff --git a/npm/react/examples/nextjs-webpack-5/cypress/support/component-index.html b/npm/react/examples/nextjs-webpack-5/cypress/support/component-index.html new file mode 100644 index 0000000000..6be8b45ce6 --- /dev/null +++ b/npm/react/examples/nextjs-webpack-5/cypress/support/component-index.html @@ -0,0 +1,13 @@ + + + + + + + Components App +
+ + +
+ + \ No newline at end of file diff --git a/npm/react/examples/nextjs-webpack-5/package.json b/npm/react/examples/nextjs-webpack-5/package.json index bc3da7b3b6..6eba372db2 100644 --- a/npm/react/examples/nextjs-webpack-5/package.json +++ b/npm/react/examples/nextjs-webpack-5/package.json @@ -3,10 +3,10 @@ "version": "0.1.0", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "dev": "next", "start": "next start", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "dependencies": { "next": "10.1.3", diff --git a/npm/react/examples/nextjs/cypress.config.js b/npm/react/examples/nextjs/cypress.config.js new file mode 100644 index 0000000000..b1b424f599 --- /dev/null +++ b/npm/react/examples/nextjs/cypress.config.js @@ -0,0 +1,14 @@ +const { devServer } = require('@cypress/react/plugins/next') + +module.exports = { + 'video': false, + 'viewportWidth': 500, + 'viewportHeight': 800, + 'experimentalFetchPolyfill': true, + 'env': { + 'coverage': true, + }, + 'component': { + devServer, + }, +} diff --git a/npm/react/examples/nextjs/cypress.json b/npm/react/examples/nextjs/cypress.json deleted file mode 100644 index a281a06f60..0000000000 --- a/npm/react/examples/nextjs/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "testFiles": "**/*.spec.{js,jsx}", - "viewportWidth": 500, - "viewportHeight": 800, - "experimentalFetchPolyfill": true, - "componentFolder": "cypress/components", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/nextjs/cypress/components/HelloWorld.spec.jsx b/npm/react/examples/nextjs/cypress/components/HelloWorld.cy.jsx similarity index 100% rename from npm/react/examples/nextjs/cypress/components/HelloWorld.spec.jsx rename to npm/react/examples/nextjs/cypress/components/HelloWorld.cy.jsx diff --git a/npm/react/examples/nextjs/cypress/components/Page.cy.jsx b/npm/react/examples/nextjs/cypress/components/Page.cy.jsx new file mode 100644 index 0000000000..27f1a0dc6b --- /dev/null +++ b/npm/react/examples/nextjs/cypress/components/Page.cy.jsx @@ -0,0 +1,38 @@ +/// +import * as React from 'react' +import IndexPage from '../../pages/index' +import { mount } from '@cypress/react' + +describe('NextJS page', () => { + it('Renders page component', () => { + mount() + + cy.contains('Welcome to Next.js') + cy.get('[aria-label=search]').type('Cypress') + cy.contains('.search-text', 'You are searching for: Cypress') + }) + + it(`It doesn't run the .getInitialProps()`, () => { + mount() + + cy.get('[data-testid="server-result"').should('not.exist') + }) + + it('Allows to manually mock the server side props', () => { + mount() + + cy.contains( + '`.getInitialProps()` was called and passed props to this component', + ) + }) + + it('can be tested with real .getInitialProps call', () => { + cy + .wrap(IndexPage.getServerSideProps()) + .then((props) => mount()) + + cy.contains( + '`.getInitialProps()` was called and passed props to this component', + ) + }) +}) diff --git a/npm/react/examples/nextjs/cypress/components/Page.spec.jsx b/npm/react/examples/nextjs/cypress/components/Page.spec.jsx deleted file mode 100644 index 879f84da62..0000000000 --- a/npm/react/examples/nextjs/cypress/components/Page.spec.jsx +++ /dev/null @@ -1,38 +0,0 @@ -/// -import * as React from 'react' -import IndexPage from '../../pages/index' -import { mount } from '@cypress/react' - -describe('NextJS page', () => { - it('Renders page component', () => { - mount() - - cy.contains('Welcome to Next.js') - cy.get('[aria-label=search]').type('Cypress') - cy.contains('.search-text', 'You are searching for: Cypress') - }) - - it('It doesn\'t run the `.getInitialProps()`', () => { - mount() - - cy.get('[data-testid="server-result"').should('not.exist') - }) - - it('Allows to manually mock the server side props', () => { - mount() - - cy.contains( - '`.getInitialProps()` was called and passed props to this component', - ) - }) - - it('can be tested with real .getInitialProps call', () => { - cy - .wrap(IndexPage.getServerSideProps()) - .then((props) => mount()) - - cy.contains( - '`.getInitialProps()` was called and passed props to this component', - ) - }) -}) diff --git a/npm/react/examples/nextjs/cypress/components/Router.spec.jsx b/npm/react/examples/nextjs/cypress/components/Router.cy.jsx similarity index 100% rename from npm/react/examples/nextjs/cypress/components/Router.spec.jsx rename to npm/react/examples/nextjs/cypress/components/Router.cy.jsx diff --git a/npm/react/examples/nextjs/cypress/components/Search.spec.jsx b/npm/react/examples/nextjs/cypress/components/Search.cy.jsx similarity index 100% rename from npm/react/examples/nextjs/cypress/components/Search.spec.jsx rename to npm/react/examples/nextjs/cypress/components/Search.cy.jsx diff --git a/npm/react/examples/a11y/cypress/integration/cy-spec.js b/npm/react/examples/nextjs/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/a11y/cypress/integration/cy-spec.js rename to npm/react/examples/nextjs/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/nextjs/cypress/plugins/index.js b/npm/react/examples/nextjs/cypress/plugins/index.js deleted file mode 100644 index 3edcd42978..0000000000 --- a/npm/react/examples/nextjs/cypress/plugins/index.js +++ /dev/null @@ -1,10 +0,0 @@ -const devServer = require('@cypress/react/plugins/next') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - return config -} diff --git a/npm/react/examples/nextjs/cypress/support/component-index.html b/npm/react/examples/nextjs/cypress/support/component-index.html new file mode 100644 index 0000000000..6be8b45ce6 --- /dev/null +++ b/npm/react/examples/nextjs/cypress/support/component-index.html @@ -0,0 +1,13 @@ + + + + + + + Components App +
+ + +
+ + \ No newline at end of file diff --git a/npm/react/examples/nextjs/cypress/support/index.js b/npm/react/examples/nextjs/cypress/support/component.js similarity index 100% rename from npm/react/examples/nextjs/cypress/support/index.js rename to npm/react/examples/nextjs/cypress/support/component.js diff --git a/npm/react/examples/nextjs/package.json b/npm/react/examples/nextjs/package.json index e81f06c656..4db881e2ac 100644 --- a/npm/react/examples/nextjs/package.json +++ b/npm/react/examples/nextjs/package.json @@ -6,11 +6,11 @@ "build": "next build", "build:static": "next build && next out", "check-coverage": "check-coverage components/Search.jsx && check-coverage pages/index.js && check-coverage pages/router.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "dev": "next", "only-covered": "only-covered components/Search.jsx pages/index.js pages/router.js", "start": "next start", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/react-scripts-folder/cypress.config.js b/npm/react/examples/react-scripts-folder/cypress.config.js new file mode 100644 index 0000000000..901908c846 --- /dev/null +++ b/npm/react/examples/react-scripts-folder/cypress.config.js @@ -0,0 +1,13 @@ +const { devServer } = require('@cypress/react/plugins/react-scripts') + +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 800, + 'component': { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + devServer, + }, +} diff --git a/npm/react/examples/react-scripts-folder/cypress.json b/npm/react/examples/react-scripts-folder/cypress.json deleted file mode 100644 index a595a1acd3..0000000000 --- a/npm/react/examples/react-scripts-folder/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "cypress/component" -} \ No newline at end of file diff --git a/npm/react/examples/react-scripts-folder/cypress/component/App.cy-spec.js b/npm/react/examples/react-scripts-folder/cypress/component/App.cy.js similarity index 100% rename from npm/react/examples/react-scripts-folder/cypress/component/App.cy-spec.js rename to npm/react/examples/react-scripts-folder/cypress/component/App.cy.js diff --git a/npm/react/examples/nextjs/cypress/integration/cy.spec.js b/npm/react/examples/react-scripts-folder/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/nextjs/cypress/integration/cy.spec.js rename to npm/react/examples/react-scripts-folder/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/react-scripts-folder/cypress/plugins/index.js b/npm/react/examples/react-scripts-folder/cypress/plugins/index.js deleted file mode 100644 index 33bce3362b..0000000000 --- a/npm/react/examples/react-scripts-folder/cypress/plugins/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/react-scripts-folder/cypress/support/component-index.html b/npm/react/examples/react-scripts-folder/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/react-scripts-folder/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/react-scripts-folder/cypress/support/index.js b/npm/react/examples/react-scripts-folder/cypress/support/component.js similarity index 100% rename from npm/react/examples/react-scripts-folder/cypress/support/index.js rename to npm/react/examples/react-scripts-folder/cypress/support/component.js diff --git a/npm/react/examples/react-scripts-folder/package.json b/npm/react/examples/react-scripts-folder/package.json index 0c8dbe057a..0f4cd36bb8 100644 --- a/npm/react/examples/react-scripts-folder/package.json +++ b/npm/react/examples/react-scripts-folder/package.json @@ -5,9 +5,9 @@ "private": true, "scripts": { "check-coverage": "check-coverage src/App.js src/calc.js src/Child.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered src/App.js src/calc.js src/Child.js", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/react-scripts-folder/src/Logo.cy-spec.js b/npm/react/examples/react-scripts-folder/src/Logo.cy.js similarity index 100% rename from npm/react/examples/react-scripts-folder/src/Logo.cy-spec.js rename to npm/react/examples/react-scripts-folder/src/Logo.cy.js diff --git a/npm/react/examples/react-scripts-typescript/cypress.config.js b/npm/react/examples/react-scripts-typescript/cypress.config.js new file mode 100644 index 0000000000..a98c0d52fb --- /dev/null +++ b/npm/react/examples/react-scripts-typescript/cypress.config.js @@ -0,0 +1,11 @@ +const { defineConfig } = require('cypress') +const { devServer } = require('@cypress/react/plugins/react-scripts') + +module.exports = defineConfig({ + 'video': false, + 'viewportWidth': 500, + 'viewportHeight': 800, + 'component': { + devServer, + }, +}) diff --git a/npm/react/examples/react-scripts-typescript/cypress.json b/npm/react/examples/react-scripts-typescript/cypress.json deleted file mode 100644 index 67ebf9f708..0000000000 --- a/npm/react/examples/react-scripts-typescript/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.tsx", - "viewportWidth": 500, - "viewportHeight": 800, - "componentFolder": "src" -} diff --git a/npm/react/examples/react-scripts-folder/cypress/integration/cy-spec.js b/npm/react/examples/react-scripts-typescript/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/react-scripts-folder/cypress/integration/cy-spec.js rename to npm/react/examples/react-scripts-typescript/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/react-scripts-typescript/cypress/plugins/index.js b/npm/react/examples/react-scripts-typescript/cypress/plugins/index.js deleted file mode 100644 index ac64296b4e..0000000000 --- a/npm/react/examples/react-scripts-typescript/cypress/plugins/index.js +++ /dev/null @@ -1,10 +0,0 @@ -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - return config -} diff --git a/npm/react/examples/react-scripts-typescript/cypress/support/component-index.html b/npm/react/examples/react-scripts-typescript/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/react-scripts-typescript/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/react-scripts-typescript/cypress/support/index.ts b/npm/react/examples/react-scripts-typescript/cypress/support/component.ts similarity index 100% rename from npm/react/examples/react-scripts-typescript/cypress/support/index.ts rename to npm/react/examples/react-scripts-typescript/cypress/support/component.ts diff --git a/npm/react/examples/react-scripts-typescript/package.json b/npm/react/examples/react-scripts-typescript/package.json index 59636f115c..4fda13ea41 100644 --- a/npm/react/examples/react-scripts-typescript/package.json +++ b/npm/react/examples/react-scripts-typescript/package.json @@ -1,9 +1,14 @@ { "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "start": "react-scripts start", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" + }, + "dependencies": { + "react": "^17.0.1", + "react-dom": "^17.0.1", + "react-scripts": "4.0.3" }, "devDependencies": { "@cypress/react": "file:../../dist", @@ -11,9 +16,6 @@ "@types/react-dom": "^17.0.0", "mocha-junit-reporter": "^2.0.0", "mocha-multi-reporters": "^1.5.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-scripts": "4.0.3", "typescript": "^4.2.3" } } diff --git a/npm/react/examples/react-scripts-typescript/src/App.cy-spec.tsx b/npm/react/examples/react-scripts-typescript/src/App.cy.tsx similarity index 100% rename from npm/react/examples/react-scripts-typescript/src/App.cy-spec.tsx rename to npm/react/examples/react-scripts-typescript/src/App.cy.tsx diff --git a/npm/react/examples/react-scripts-typescript/yarn.lock b/npm/react/examples/react-scripts-typescript/yarn.lock new file mode 100644 index 0000000000..4fbdeaa2cb --- /dev/null +++ b/npm/react/examples/react-scripts-typescript/yarn.lock @@ -0,0 +1,11432 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.5.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.12.1", "@babel/compat-data@^7.13.11", "@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.12.3": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" + integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5", "@babel/core@^7.8.4": + version "7.15.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" + integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helpers" "^7.15.4" + "@babel/parser" "^7.15.5" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.12.1", "@babel/generator@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" + integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== + dependencies: + "@babel/types" "^7.15.4" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" + integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz#21ad815f609b84ee0e3058676c33cf6d1670525f" + integrity sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-compilation-targets@^7.12.1", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" + integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.12.1", "@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" + integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + +"@babel/helper-create-regexp-features-plugin@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" + integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" + integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz#f9aec9d219f271eaf92b9f561598ca6b2682600c" + integrity sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g== + dependencies: + "@babel/types" "^7.15.4" + +"@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.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.1", "@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.12.1", "@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.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", "@babel/helper-remap-async-to-generator@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f" + integrity sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-wrap-function" "^7.15.4" + "@babel/types" "^7.15.4" + +"@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.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.12.1", "@babel/helper-skip-transparent-expression-wrappers@^7.14.5", "@babel/helper-skip-transparent-expression-wrappers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz#707dbdba1f4ad0fa34f9114fc8197aec7d5da2eb" + integrity sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A== + dependencies: + "@babel/types" "^7.15.4" + +"@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.12.1", "@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.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz#6f754b2446cfaf3d612523e6ab8d79c27c3a3de7" + integrity sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw== + dependencies: + "@babel/helper-function-name" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helpers@^7.12.1", "@babel/helpers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" + integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== + dependencies: + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.12.3", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.0": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" + integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz#dbdeabb1e80f622d9f0b583efb2999605e0a567e" + integrity sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + +"@babel/plugin-proposal-async-generator-functions@^7.12.1", "@babel/plugin-proposal-async-generator-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz#f82aabe96c135d2ceaa917feb9f5fca31635277e" + integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.15.4" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz#a082ff541f2a29a4821065b8add9346c0c16e5de" + integrity sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" + integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz#3e7ca6128453c089e8b477a99f970c63fc1cb8d7" + integrity sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.1.tgz#59271439fed4145456c41067450543aee332d15f" + integrity sha512-knNIuusychgYN8fGJHONL0RbFxLGawhXOJNLBk75TniTsZZeA+wdkDuv6wp4lGwzQEKjZi6/WYtnb3udNPmQmQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.12.1" + +"@babel/plugin-proposal-dynamic-import@^7.12.1", "@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" + integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.12.1", "@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" + integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.12.1", "@babel/plugin-proposal-json-strings@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" + integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.12.1", "@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" + integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" + integrity sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" + integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.1.tgz#0e2c6774c4ce48be412119b4d693ac777f7685a6" + integrity sha512-MR7Ok+Af3OhNTCxYVjJZHS0t97ydnJZt/DbR4WISO39iDnhiD8XHrY12xuSJ90FFEGjir0Fzyyn7g/zY6hxbxA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-numeric-separator@^7.12.1", "@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" + integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.15.6": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" + integrity sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.15.4" + +"@babel/plugin-proposal-optional-catch-binding@^7.12.1", "@babel/plugin-proposal-optional-catch-binding@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" + integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz#cce122203fc8a32794296fc377c6dedaf4363797" + integrity sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.12.1", "@babel/plugin-proposal-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" + integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.12.1", "@babel/plugin-proposal-private-methods@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" + integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz#55c5e3b4d0261fd44fe637e3f624cfb0f484e3e5" + integrity sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.12.1", "@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" + integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.12.1": + 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.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-flow@^7.12.1": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz#2ff654999497d7d7d142493260005263731da180" + integrity sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" + integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.12.1", "@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" + integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.12.1", "@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" + integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-async-to-generator@^7.12.1", "@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + +"@babel/plugin-transform-block-scoped-functions@^7.12.1", "@babel/plugin-transform-block-scoped-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" + integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-block-scoping@^7.12.1", "@babel/plugin-transform-block-scoping@^7.15.3": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz#50aee17aaf7f332ae44e3bce4c2e10534d5d3bf1" + integrity sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.12.1", "@babel/plugin-transform-computed-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" + integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.12.1", "@babel/plugin-transform-destructuring@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" + integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.12.1", "@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" + integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-duplicate-keys@^7.12.1", "@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" + integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.12.1", "@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" + integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-flow-strip-types@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz#8430decfa7eb2aea5414ed4a3fa6e1652b7d77c4" + integrity sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.12.1" + +"@babel/plugin-transform-for-of@^7.12.1", "@babel/plugin-transform-for-of@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz#25c62cce2718cfb29715f416e75d5263fb36a8c2" + integrity sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.12.1", "@babel/plugin-transform-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" + integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.12.1", "@babel/plugin-transform-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" + integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.12.1", "@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" + integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.12.1", "@babel/plugin-transform-modules-amd@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" + integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.12.1", "@babel/plugin-transform-modules-commonjs@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz#8201101240eabb5a76c08ef61b2954f767b6b4c1" + integrity sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA== + dependencies: + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.15.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.12.1", "@babel/plugin-transform-modules-systemjs@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz#b42890c7349a78c827719f1d2d0cd38c7d268132" + integrity sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw== + dependencies: + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.12.1", "@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.12.1", "@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" + integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + +"@babel/plugin-transform-new-target@^7.12.1", "@babel/plugin-transform-new-target@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" + integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.12.1", "@babel/plugin-transform-object-super@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" + integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.14.5" + +"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz#5f2285cc3160bf48c8502432716b48504d29ed62" + integrity sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.12.1", "@babel/plugin-transform-property-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" + integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-constant-elements@^7.12.1": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.14.5.tgz#41790d856f7c5cec82d2bcf5d0e5064d682522ed" + integrity sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-display-name@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz#1cbcd0c3b1d6648c55374a22fc9b6b7e5341c00d" + integrity sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-display-name@^7.12.1", "@babel/plugin-transform-react-display-name@^7.14.5": + version "7.15.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.15.1.tgz#6aaac6099f1fcf6589d35ae6be1b6e10c8c602b9" + integrity sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-jsx-development@^7.12.1", "@babel/plugin-transform-react-jsx-development@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.14.5.tgz#1a6c73e2f7ed2c42eebc3d2ad60b0c7494fcb9af" + integrity sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.14.5" + +"@babel/plugin-transform-react-jsx-self@^7.12.1": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.9.tgz#33041e665453391eb6ee54a2ecf3ba1d46bd30f4" + integrity sha512-Fqqu0f8zv9W+RyOnx29BX/RlEsBRANbOf5xs5oxb2aHP4FKbLXxIaVPUiCti56LAR1IixMH4EyaixhUsKqoBHw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-jsx-source@^7.12.1": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz#79f728e60e6dbd31a2b860b0bf6c9765918acf1d" + integrity sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-jsx@^7.12.1", "@babel/plugin-transform-react-jsx@^7.14.5": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz#3314b2163033abac5200a869c4de242cd50a914c" + integrity sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw== + 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.9" + +"@babel/plugin-transform-react-pure-annotations@^7.12.1", "@babel/plugin-transform-react-pure-annotations@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.14.5.tgz#18de612b84021e3a9802cbc212c9d9f46d0d11fc" + integrity sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.12.1", "@babel/plugin-transform-regenerator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" + integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.12.1", "@babel/plugin-transform-reserved-words@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" + integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-runtime@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz#04b792057eb460389ff6a4198e377614ea1e7ba5" + integrity sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-shorthand-properties@^7.12.1", "@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" + integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.12.1", "@babel/plugin-transform-spread@^7.14.6": + version "7.14.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" + integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + +"@babel/plugin-transform-sticky-regex@^7.12.1", "@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" + integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.12.1", "@babel/plugin-transform-template-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" + integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.12.1", "@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" + integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typescript@^7.12.1": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.4.tgz#db7a062dcf8be5fc096bc0eeb40a13fbfa1fa251" + integrity sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.14.5" + +"@babel/plugin-transform-unicode-escapes@^7.12.1", "@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" + integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.12.1", "@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" + integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.1.tgz#9c7e5ca82a19efc865384bb4989148d2ee5d7ac2" + integrity sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg== + dependencies: + "@babel/compat-data" "^7.12.1" + "@babel/helper-compilation-targets" "^7.12.1" + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-validator-option" "^7.12.1" + "@babel/plugin-proposal-async-generator-functions" "^7.12.1" + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-dynamic-import" "^7.12.1" + "@babel/plugin-proposal-export-namespace-from" "^7.12.1" + "@babel/plugin-proposal-json-strings" "^7.12.1" + "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-numeric-separator" "^7.12.1" + "@babel/plugin-proposal-object-rest-spread" "^7.12.1" + "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.1" + "@babel/plugin-proposal-private-methods" "^7.12.1" + "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.12.1" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.12.1" + "@babel/plugin-transform-arrow-functions" "^7.12.1" + "@babel/plugin-transform-async-to-generator" "^7.12.1" + "@babel/plugin-transform-block-scoped-functions" "^7.12.1" + "@babel/plugin-transform-block-scoping" "^7.12.1" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-computed-properties" "^7.12.1" + "@babel/plugin-transform-destructuring" "^7.12.1" + "@babel/plugin-transform-dotall-regex" "^7.12.1" + "@babel/plugin-transform-duplicate-keys" "^7.12.1" + "@babel/plugin-transform-exponentiation-operator" "^7.12.1" + "@babel/plugin-transform-for-of" "^7.12.1" + "@babel/plugin-transform-function-name" "^7.12.1" + "@babel/plugin-transform-literals" "^7.12.1" + "@babel/plugin-transform-member-expression-literals" "^7.12.1" + "@babel/plugin-transform-modules-amd" "^7.12.1" + "@babel/plugin-transform-modules-commonjs" "^7.12.1" + "@babel/plugin-transform-modules-systemjs" "^7.12.1" + "@babel/plugin-transform-modules-umd" "^7.12.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" + "@babel/plugin-transform-new-target" "^7.12.1" + "@babel/plugin-transform-object-super" "^7.12.1" + "@babel/plugin-transform-parameters" "^7.12.1" + "@babel/plugin-transform-property-literals" "^7.12.1" + "@babel/plugin-transform-regenerator" "^7.12.1" + "@babel/plugin-transform-reserved-words" "^7.12.1" + "@babel/plugin-transform-shorthand-properties" "^7.12.1" + "@babel/plugin-transform-spread" "^7.12.1" + "@babel/plugin-transform-sticky-regex" "^7.12.1" + "@babel/plugin-transform-template-literals" "^7.12.1" + "@babel/plugin-transform-typeof-symbol" "^7.12.1" + "@babel/plugin-transform-unicode-escapes" "^7.12.1" + "@babel/plugin-transform-unicode-regex" "^7.12.1" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.12.1" + core-js-compat "^3.6.2" + semver "^5.5.0" + +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.8.4": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" + integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" + "@babel/plugin-proposal-async-generator-functions" "^7.15.4" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.15.4" + "@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.15.6" + "@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.15.4" + "@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.15.3" + "@babel/plugin-transform-classes" "^7.15.4" + "@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.15.4" + "@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.15.4" + "@babel/plugin-transform-modules-systemjs" "^7.15.4" + "@babel/plugin-transform-modules-umd" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" + "@babel/plugin-transform-new-target" "^7.14.5" + "@babel/plugin-transform-object-super" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.15.4" + "@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.15.6" + 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.16.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.3", "@babel/preset-modules@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.12.1.tgz#7f022b13f55b6dd82f00f16d1c599ae62985358c" + integrity sha512-euCExymHCi0qB9u5fKw7rvlw7AZSjw/NaB9h7EkdTt5+yHRrXdiRTh7fkG3uBPpJg82CqLfp1LHLqWGSCrab+g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.12.1" + "@babel/plugin-transform-react-jsx" "^7.12.1" + "@babel/plugin-transform-react-jsx-development" "^7.12.1" + "@babel/plugin-transform-react-jsx-self" "^7.12.1" + "@babel/plugin-transform-react-jsx-source" "^7.12.1" + "@babel/plugin-transform-react-pure-annotations" "^7.12.1" + +"@babel/preset-react@^7.12.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.14.5.tgz#0fbb769513f899c2c56f3a882fa79673c2d4ab3c" + integrity sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-react-display-name" "^7.14.5" + "@babel/plugin-transform-react-jsx" "^7.14.5" + "@babel/plugin-transform-react-jsx-development" "^7.14.5" + "@babel/plugin-transform-react-pure-annotations" "^7.14.5" + +"@babel/preset-typescript@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.12.1.tgz#86480b483bb97f75036e8864fe404cc782cc311b" + integrity sha512-hNK/DhmoJPsksdHuI/RVrcEws7GN5eamhi28JkO52MqIxU8Z0QpmiSOQxZHWOHV7I3P4UjHV97ay4TcamMA6Kw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-typescript" "^7.12.1" + +"@babel/runtime-corejs3@^7.10.2": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz#403139af262b9a6e8f9ba04a6fdcebf8de692bf1" + integrity sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg== + dependencies: + core-js-pure "^3.16.0" + regenerator-runtime "^0.13.4" + +"@babel/runtime@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" + integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.10.4", "@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.12.1", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.0": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" + integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.6", "@babel/types@^7.14.9", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" + integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@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/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@csstools/normalize.css@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" + integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== + +"@cypress/react@file:../../dist": + version "0.0.0" + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@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== + +"@hapi/address@2.x.x": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== + +"@hapi/bourne@1.x.x": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" + integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== + +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/joi@^15.1.0": + version "15.1.1" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" + integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== + dependencies: + "@hapi/address" "2.x.x" + "@hapi/bourne" "1.x.x" + "@hapi/hoek" "8.x.x" + "@hapi/topo" "3.x.x" + +"@hapi/topo@3.x.x": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== + dependencies: + "@hapi/hoek" "^8.3.0" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + +"@jest/core@^26.6.0", "@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" + micromatch "^4.0.2" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^26.6.0", "@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== + dependencies: + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== + dependencies: + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^7.0.0" + optionalDependencies: + node-notifier "^8.0.0" + +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^26.6.0", "@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== + dependencies: + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.0", "@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@npmcli/fs@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@pmmmwh/react-refresh-webpack-plugin@0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" + integrity sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ== + dependencies: + ansi-html "^0.0.7" + error-stack-parser "^2.0.6" + html-entities "^1.2.1" + native-url "^0.2.6" + schema-utils "^2.6.5" + source-map "^0.7.3" + +"@rollup/plugin-node-resolve@^7.1.1": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca" + integrity sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q== + dependencies: + "@rollup/pluginutils" "^3.0.8" + "@types/resolve" "0.0.8" + builtin-modules "^3.1.0" + is-module "^1.0.0" + resolve "^1.14.2" + +"@rollup/plugin-replace@^2.3.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a" + integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + magic-string "^0.25.7" + +"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@surma/rollup-plugin-off-main-thread@^1.1.1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz#e6786b6af5799f82f7ab3a82e53f6182d2b91a58" + integrity sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A== + dependencies: + ejs "^2.6.1" + magic-string "^0.25.0" + +"@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.5.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" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.16" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/eslint@^7.2.6": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.0.tgz#7e41f2481d301c68e14f483fe10b017753ce8d5a" + integrity sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/glob@^7.1.1": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/html-minifier-terser@^5.0.0": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" + integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/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": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "16.10.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5" + integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prettier@^2.0.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" + integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== + +"@types/prop-types@*": + 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/react-dom@^17.0.0": + version "17.0.9" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add" + integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^17.0.0": + version "17.0.27" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.27.tgz#6498ed9b3ad117e818deb5525fa1946c09f2e0e6" + integrity sha512-zgiJwtsggVGtr53MndV7jfiUESTqrbxOcBvwfe6KS/9bzaVPCTDieTWnFNecVNx6EAaapg5xsLLWFfHHR437AA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/resolve@0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" + integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== + dependencies: + "@types/node" "*" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/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/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/webpack-sources@*": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b" + integrity sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.7.3" + +"@types/webpack@^4.41.8": + version "4.41.31" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.31.tgz#c35f252a3559ddf9c85c0d8b0b42019025e581aa" + integrity sha512-/i0J7sepXFIp1ZT7FjUGi1eXMCg8HCCzLJEQkKsOtbJFontsJLolBcDC+3qxn5pPwiCt1G0ZdRmYRzNBtvpuGQ== + dependencies: + "@types/node" "*" + "@types/tapable" "^1" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + anymatch "^3.0.0" + source-map "^0.6.0" + +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^15.0.0": + version "15.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^4.5.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/experimental-utils@^3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz#e179ffc81a80ebcae2ea04e0332f8b251345a686" + integrity sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/types" "3.10.1" + "@typescript-eslint/typescript-estree" "3.10.1" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^4.5.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" + integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/typescript-estree@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" + integrity sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w== + dependencies: + "@typescript-eslint/types" "3.10.1" + "@typescript-eslint/visitor-keys" "3.10.1" + debug "^4.1.1" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" + integrity sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ== + dependencies: + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== + dependencies: + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + +"@webassemblyjs/floating-point-hex-parser@1.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.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.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-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.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.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.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.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.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.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.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.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.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" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +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== + +accepts@~1.3.4, 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@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== + +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== + +adjust-sourcemap-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz#5ae12fb5b7b1c585e80bbb5a63ec163a1a45e61e" + integrity sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw== + dependencies: + loader-utils "^2.0.0" + regex-parser "^2.2.11" + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.6.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" + integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html@0.0.7, ansi-html@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0, 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@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +aria-query@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" + integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== + dependencies: + "@babel/runtime" "^7.10.2" + "@babel/runtime-corejs3" "^7.10.2" + +arity-n@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" + integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U= + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.1.1, array-includes@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +array.prototype.flat@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +array.prototype.flatmap@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +asap@~2.0.6: + 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" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + 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@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^9.6.1: + version "9.8.8" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +axe-core@^4.0.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.3.tgz#b55cd8e8ddf659fe89b064680e1c6a4dceab0325" + integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA== + +axobject-query@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" + integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== + +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-extract-comments@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21" + integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ== + dependencies: + babylon "^6.18.0" + +babel-jest@^26.6.0, babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-loader@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" + integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== + dependencies: + find-cache-dir "^2.1.0" + loader-utils "^1.4.0" + mkdirp "^0.5.3" + pify "^4.0.1" + schema-utils "^2.6.5" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-macros@2.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-named-asset-import@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz#156cd55d3f1228a5765774340937afc8398067dd" + integrity sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw== + +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" + integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.2: + version "0.2.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.16.2" + +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-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-remove-prop-types@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-react-app@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.0.tgz#689b60edc705f8a70ce87f47ab0e560a317d7045" + integrity sha512-itL2z8v16khpuKutx5IH8UdCdSTuzrOhRFTEdIhveZ2i1iBKDrVE0ATa4sFVy+02GLucZNVBWtoarXBy0Msdpg== + dependencies: + "@babel/core" "7.12.3" + "@babel/plugin-proposal-class-properties" "7.12.1" + "@babel/plugin-proposal-decorators" "7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "7.12.1" + "@babel/plugin-proposal-numeric-separator" "7.12.1" + "@babel/plugin-proposal-optional-chaining" "7.12.1" + "@babel/plugin-transform-flow-strip-types" "7.12.1" + "@babel/plugin-transform-react-display-name" "7.12.1" + "@babel/plugin-transform-runtime" "7.12.1" + "@babel/preset-env" "7.12.1" + "@babel/preset-react" "7.12.1" + "@babel/preset-typescript" "7.12.1" + "@babel/runtime" "7.12.1" + babel-plugin-macros "2.8.0" + babel-plugin-transform-react-remove-prop-types "0.4.24" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +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== + +base64-js@^1.0.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bfj@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2" + integrity sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw== + dependencies: + bluebird "^3.5.5" + check-types "^11.1.1" + hoopy "^0.1.4" + tryer "^1.0.1" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.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= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@4.14.2: + version "4.14.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.2.tgz#1b3cec458a1ba87588cc5e9be62f19b6d48813ce" + integrity sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw== + dependencies: + caniuse-lite "^1.0.30001125" + electron-to-chromium "^1.3.564" + escalade "^3.0.2" + node-releases "^1.1.61" + +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.17.3, browserslist@^4.6.2, browserslist@^4.6.4: + version "4.17.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" + integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== + dependencies: + caniuse-lite "^1.0.30001264" + electron-to-chromium "^1.3.857" + escalade "^3.1.1" + node-releases "^1.1.77" + picocolors "^0.2.1" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +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" + +builtin-modules@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" + integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== + +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= + +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== + +cacache@^12.0.2: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cacache@^15.0.5: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0, camelcase@^6.1.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-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001264: + version "1.0.30001265" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" + integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +case-sensitive-paths-webpack-plugin@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7" + integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ== + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + 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" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +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@^11.1.1: + version "11.1.2" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.1.2.tgz#86a7c12bf5539f6324eb0e70ca8896c0e38f3e2f" + integrity sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ== + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +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" + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" + integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compose-function@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" + integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8= + dependencies: + arity-n "^1.0.4" + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +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" + +confusing-browser-globals@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" + integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +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== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" + integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= + +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" + 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.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== + +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= + +core-js-compat@^3.16.0, core-js-compat@^3.16.2, core-js-compat@^3.6.2: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.18.2.tgz#e40c266fbd613948dd8d2d2156345da8ac03c142" + integrity sha512-25VJYCJtGjZwLguj7d66oiHfmnVw3TMOZ0zV8DyMJp/aeQ3OjR519iOOeck08HMyVVRAqXxafc2Hl+5QstJrsQ== + dependencies: + browserslist "^4.17.3" + semver "7.0.0" + +core-js-pure@^3.16.0: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.18.2.tgz#d8cc11d4885ea919f3de776d45e720e4c769d406" + integrity sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA== + +core-js@^2.4.0: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-js@^3.6.5: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.2.tgz#63a551e8a29f305cd4123754846e65896619ba5b" + integrity sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ== + +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== + +cosmiconfig@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +cosmiconfig@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +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@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= + +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-loader@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e" + integrity sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg== + dependencies: + camelcase "^6.0.0" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^2.0.0" + postcss "^7.0.32" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.3" + postcss-modules-scope "^2.2.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.1.0" + schema-utils "^2.7.1" + semver "^7.3.2" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== + +css@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" + integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.3" + postcss-unique-selectors "^4.0.1" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.11" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" + integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.8" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +csstype@^3.0.2: + version "3.0.9" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b" + integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw== + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +damerau-levenshtein@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" + integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^3.1.1, debug@^3.2.6, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +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.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + 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" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +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= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +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= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +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" + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== + dependencies: + domelementtype "^2.2.0" + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +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@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + +duplexer@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +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== + +electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.857: + version "1.3.860" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.860.tgz#d612e54ed75fa524c12af8da3ad8121ebfe2802b" + integrity sha512-gWwGZ+Wv4Mou2SJRH6JQzhTPjL5f95SX7n6VkLTQ/Q/INsZLZNQ1vH2GlZjozKyvT0kkFuCmWTwIoCj+/hUDPw== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.0.0: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.3.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" + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" + integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== + dependencies: + stackframe "^1.1.1" + +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.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" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +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= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escalade@^3.0.2, escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-react-app@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz#ccff9fc8e36b322902844cbd79197982be355a0e" + integrity sha512-bpoAAC+YRfzq0dsTk+6v9aHm/uqnDwayNAXleMypGl6CpxI9oXXscVHo4fk3eJPIn+rsbtNetB4r/ZIidFIE8A== + dependencies: + confusing-browser-globals "^1.0.10" + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534" + integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q== + dependencies: + debug "^3.2.7" + pkg-dir "^2.0.0" + +eslint-plugin-flowtype@^5.2.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz#7764cc63940f215bf3f0bd2d9a1293b2b9b2b4bb" + integrity sha512-vcz32f+7TP+kvTUyMXZmCnNujBQZDNmcqPImw8b9PZ+16w1Qdm6ryRuYZYVaG9xRqqmAPr2Cs9FAX5gN+x/bjw== + dependencies: + lodash "^4.17.15" + string-natural-compare "^3.0.1" + +eslint-plugin-import@^2.22.1: + version "2.24.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz#2c8cd2e341f3885918ee27d18479910ade7bb4da" + integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q== + dependencies: + array-includes "^3.1.3" + array.prototype.flat "^1.2.4" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.6.2" + find-up "^2.0.0" + has "^1.0.3" + is-core-module "^2.6.0" + minimatch "^3.0.4" + object.values "^1.1.4" + pkg-up "^2.0.0" + read-pkg-up "^3.0.0" + resolve "^1.20.0" + tsconfig-paths "^3.11.0" + +eslint-plugin-jest@^24.1.0: + version "24.5.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.5.2.tgz#f71f98f27fd18b50f55246ca090f36d1730e36a6" + integrity sha512-lrI3sGAyZi513RRmP08sIW241Ti/zMnn/6wbE4ZBhb3M2pJ9ztaZMnSKSKKBUfotVdwqU8W1KtD8ao2/FR8DIg== + dependencies: + "@typescript-eslint/experimental-utils" "^4.0.1" + +eslint-plugin-jsx-a11y@^6.3.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" + integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== + dependencies: + "@babel/runtime" "^7.11.2" + aria-query "^4.2.2" + array-includes "^3.1.1" + ast-types-flow "^0.0.7" + axe-core "^4.0.2" + axobject-query "^2.2.0" + damerau-levenshtein "^1.0.6" + emoji-regex "^9.0.0" + has "^1.0.3" + jsx-ast-utils "^3.1.0" + language-tags "^1.0.5" + +eslint-plugin-react-hooks@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" + integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== + +eslint-plugin-react@^7.21.5: + version "7.26.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz#41bcfe3e39e6a5ac040971c1af94437c80daa40e" + integrity sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ== + dependencies: + array-includes "^3.1.3" + array.prototype.flatmap "^1.2.4" + doctrine "^2.1.0" + estraverse "^5.2.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.0.4" + object.entries "^1.1.4" + object.fromentries "^2.0.4" + object.hasown "^1.0.0" + object.values "^1.1.4" + prop-types "^15.7.2" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.5" + +eslint-plugin-testing-library@^3.9.2: + version "3.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.2.tgz#609ec2b0369da7cf2e6d9edff5da153cc31d87bd" + integrity sha512-WAmOCt7EbF1XM8XfbCKAEzAPnShkNSwcIsAD2jHdsMUT9mZJPjLCG7pMzbcC8kK366NOuGip8HKLDC+Xk4yIdA== + dependencies: + "@typescript-eslint/experimental-utils" "^3.10.1" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-webpack-plugin@^2.5.2: + version "2.5.4" + resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.4.tgz#473b84932f1a8e2c2b8e66a402d0497bf440b986" + integrity sha512-7rYh0m76KyKSDE+B+2PUQrlNS4HJ51t3WKpkJg6vo2jFMbEPTG99cBV0Dm7LXSHucN4WGCG65wQcRiTFrj7iWw== + dependencies: + "@types/eslint" "^7.2.6" + arrify "^2.0.1" + jest-worker "^26.6.2" + micromatch "^4.0.2" + normalize-path "^3.0.0" + schema-utils "^3.0.0" + +eslint@^7.11.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0, esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +estree-walker@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" + integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== + +estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + dependencies: + original "^1.0.0" + +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.3.2: + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expect@^26.6.0, expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext@^1.1.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== + dependencies: + 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= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.1.1.tgz#a6f29dfb3f5933a1c350b2dbaa20ac5be0539baa" + integrity sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.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== + +filesize@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" + integrity sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.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.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +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, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== + +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.14.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" + integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fork-ts-checker-webpack-plugin@4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" + integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== + dependencies: + "@babel/code-frame" "^7.5.5" + chalk "^2.4.1" + micromatch "^3.1.10" + minimatch "^3.0.4" + semver "^5.6.0" + tapable "^1.0.0" + worker-rpc "^0.1.0" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@^2.1.2, fsevents@^2.1.3, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +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= + +gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-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== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + 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= + +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.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + 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" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" + integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== + dependencies: + type-fest "^0.20.2" + +globby@11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +gzip-size@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +harmony-reflect@^1.4.6: + version "1.6.2" + resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" + integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +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" + +hoopy@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-entities@^1.2.1, html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier-terser@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" + integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== + dependencies: + camel-case "^4.1.1" + clean-css "^4.2.3" + commander "^4.1.1" + he "^1.2.0" + param-case "^3.0.3" + relateurl "^0.2.7" + terser "^4.6.3" + +html-webpack-plugin@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz#625097650886b97ea5dae331c320e3238f6c121c" + integrity sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw== + 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.15" + pretty-error "^2.1.1" + tapable "^1.1.3" + util.promisify "1.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +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.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +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" + +identity-obj-proxy@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" + integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= + dependencies: + harmony-reflect "^1.4.6" + +ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4, ignore@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +immer@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" + integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +import-local@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3, infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +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.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + 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: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + 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" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-core-module@^2.0.0, is-core-module@^2.2.0, is-core-module@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" + integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + 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" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^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.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= + +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-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + 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= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^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" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.0.4, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +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= + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-root@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + 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" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== + dependencies: + call-bind "^1.0.0" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.1.1, is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +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= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +istanbul-lib-coverage@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz#e8900b3ed6069759229cf30f7067388d148aeb5e" + integrity sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ== + +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.3.tgz#974d682037f6d12b15dc55f9a2a5f8f1ea923831" + integrity sha512-0i77ZFLsb9U3DHi22WzmIngVzfoyxxbQcZRqlF3KoKmCJGq9nhFHoGi8FqBztN2rE8w6hURnZghetn0xpkVb6A== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== + dependencies: + "@jest/types" "^26.6.2" + execa "^4.0.0" + throat "^5.0.0" + +jest-circus@26.6.0: + version "26.6.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-26.6.0.tgz#7d9647b2e7f921181869faae1f90a2629fd70705" + integrity sha512-L2/Y9szN6FJPWFK8kzWXwfp+FOR7xq0cUL4lIsdbIdwz3Vh6P1nrpcqOleSzr28zOtSHQNV9Z7Tl+KkuK7t5Ng== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.0" + "@jest/test-result" "^26.6.0" + "@jest/types" "^26.6.0" + "@types/babel__traverse" "^7.0.4" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^26.6.0" + is-generator-fn "^2.0.0" + jest-each "^26.6.0" + jest-matcher-utils "^26.6.0" + jest-message-util "^26.6.0" + jest-runner "^26.6.0" + jest-runtime "^26.6.0" + jest-snapshot "^26.6.0" + jest-util "^26.6.0" + pretty-format "^26.6.0" + stack-utils "^2.0.2" + throat "^5.0.0" + +jest-cli@^26.6.0: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== + dependencies: + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" + prompts "^2.0.1" + yargs "^15.4.1" + +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + micromatch "^4.0.2" + pretty-format "^26.6.2" + +jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + +jest-each@^26.6.0, jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" + +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^26.6.2" + is-generator-fn "^2.0.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" + throat "^5.0.0" + +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== + dependencies: + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-matcher-utils@^26.6.0, jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-message-util@^26.6.0, jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== + dependencies: + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" + +jest-resolve@26.6.0: + version "26.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.0.tgz#070fe7159af87b03e50f52ea5e17ee95bbee40e1" + integrity sha512-tRAz2bwraHufNp+CCmAD8ciyCpXCs1NQxB5EJAmtCFy6BN81loFEGWKzYu26Y62lAJJe4X4jg36Kf+NsQyiStQ== + dependencies: + "@jest/types" "^26.6.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.0" + read-pkg-up "^7.0.1" + resolve "^1.17.0" + slash "^3.0.0" + +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + +jest-runner@^26.6.0, jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" + source-map-support "^0.5.6" + throat "^5.0.0" + +jest-runtime@^26.6.0, jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.4.1" + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^26.6.0, jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + +jest-util@^26.6.0, jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== + dependencies: + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + leven "^3.1.0" + pretty-format "^26.6.2" + +jest-watch-typeahead@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.6.1.tgz#45221b86bb6710b7e97baaa1640ae24a07785e63" + integrity sha512-ITVnHhj3Jd/QkqQcTqZfRgjfyRhDFM/auzgVo2RKvSwi18YMvh0WvXDJFoFED6c7jd/5jxtu4kSOb9PTu2cPVg== + dependencies: + ansi-escapes "^4.3.1" + chalk "^4.0.0" + jest-regex-util "^26.0.0" + jest-watcher "^26.3.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + +jest-watcher@^26.3.0, jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== + dependencies: + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" + +jest-worker@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" + integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== + dependencies: + merge-stream "^2.0.0" + supports-color "^6.1.0" + +jest-worker@^26.5.0, jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest@26.6.0: + version "26.6.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.0.tgz#546b25a1d8c888569dbbe93cae131748086a4a25" + integrity sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA== + dependencies: + "@jest/core" "^26.6.0" + import-local "^3.0.2" + jest-cli "^26.6.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsdom@^16.4.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.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" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-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= + +json3@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + 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" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + dependencies: + array-includes "^3.1.3" + object.assign "^4.1.2" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +klona@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" + integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + +language-subtag-registry@~0.3.2: + version "0.3.21" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" + integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== + +language-tags@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= + dependencies: + language-subtag-registry "~0.3.2" + +last-call-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== + dependencies: + lodash "^4.17.5" + webpack-sources "^1.1.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +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-utils@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +loader-utils@2.0.0, loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +"lodash@>=3.5 <5", 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.5, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.7.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" + integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.0, magic-string@^0.25.7: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + dependencies: + sourcemap-codec "^1.4.4" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0, make-dir@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +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.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +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" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +microevent.ts@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" + integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.50.0, "mime-db@>= 1.43.0 < 2": + version "1.50.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24: + version "2.1.33" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== + dependencies: + mime-db "1.50.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz#15b0910a7f32e62ffde4a7430cfefbd700724ea6" + integrity sha512-n9BA8LonkOkW1/zn+IbLPQmovsL0wMb9yx75fMJQZf2X1Zoec9yTZtyMePcyu19wPkmFbzZZA6fLTotpFhQsOA== + dependencies: + loader-utils "^1.1.0" + normalize-url "1.9.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.1: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mocha-junit-reporter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.0.0.tgz#3bf990fce7a42c0d2b718f188553a25d9f24b9a2" + integrity sha512-20HoWh2HEfhqmigfXOKUhZQyX23JImskc37ZOhIjBKoBEsb+4cAFRJpAVhFpnvsztLklW/gFVzsrobjLwmX4lA== + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.0" + +mocha-multi-reporters@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676" + integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg== + dependencies: + debug "^4.1.1" + lodash "^4.17.15" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + +nanoid@^3.1.28: + version "3.1.29" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.29.tgz#214fb2d7a33e1a5bef4757b779dfaeb6a4e5aeb4" + integrity sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +native-url@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" + integrity sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA== + dependencies: + querystring "^0.2.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= + +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== + +neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-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-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-notifier@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + +node-releases@^1.1.61, node-releases@^1.1.77: + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== + +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.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= + +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== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.entries@^1.1.0, object.entries@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.fromentries@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.hasown@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0, object.values@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^7.0.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimize-css-assets-webpack-plugin@5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz#85883c6528aaa02e30bbad9908c92926bb52dc90" + integrity sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A== + dependencies: + cssnano "^4.1.10" + last-call-webpack-plugin "^3.0.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.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= + +p-each-series@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +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@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@3.1.0: + 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" + +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + +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" + +portfinder@^1.0.26: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + +postcss-browser-comments@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz#1248d2d935fb72053c8e1f61a84a57292d9f65e9" + integrity sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig== + dependencies: + postcss "^7" + +postcss-calc@^7.0.1: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" + integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-flexbugs-fixes@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" + integrity sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ== + dependencies: + postcss "^7.0.26" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641" + integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-initial@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53" + integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg== + dependencies: + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +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-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^3.0.3: + 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-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-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-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-8.0.1.tgz#90e80a7763d7fdf2da6f2f0f82be832ce4f66776" + integrity sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ== + dependencies: + "@csstools/normalize.css" "^10.1.0" + browserslist "^4.6.2" + postcss "^7.0.17" + postcss-browser-comments "^3.0.0" + sanitize.css "^10.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-safe-parser@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-5.0.2.tgz#459dd27df6bc2ba64608824ba39e45dacf5e852d" + integrity sha512-jDUfCPJbKOABhwpUKcqCVbbXiloe/QXMcbJ6Iipf3sDIihEzTqRCeMBfRaOHxhBuTYqtASrI1KJWxzztZU4qUQ== + dependencies: + postcss "^8.1.0" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf" + integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" + integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.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-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@7.0.36: + 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@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.1.0: + version "8.3.9" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" + integrity sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw== + dependencies: + nanoid "^3.1.28" + picocolors "^0.2.1" + source-map-js "^0.6.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +pretty-bytes@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +pretty-error@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" + integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== + dependencies: + lodash "^4.17.20" + renderkid "^2.0.4" + +pretty-format@^26.6.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" + integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== + dependencies: + asap "~2.0.6" + +prompts@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prompts@^2.0.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" + integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +proxy-addr@~2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + 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== + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystring@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-app-polyfill@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf" + integrity sha512-0sF4ny9v/B7s6aoehwze9vJNWcmCemAUYBVasscVr92+UYiEqDXOxfKjXN685mDaMRNF3WdhHQs76oTODMocFA== + dependencies: + core-js "^3.6.5" + object-assign "^4.1.1" + promise "^8.1.0" + raf "^3.4.1" + regenerator-runtime "^0.13.7" + whatwg-fetch "^3.4.1" + +react-dev-utils@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" + integrity sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A== + dependencies: + "@babel/code-frame" "7.10.4" + address "1.1.2" + browserslist "4.14.2" + chalk "2.4.2" + cross-spawn "7.0.3" + detect-port-alt "1.1.6" + escape-string-regexp "2.0.0" + filesize "6.1.0" + find-up "4.1.0" + fork-ts-checker-webpack-plugin "4.1.6" + global-modules "2.0.0" + globby "11.0.1" + gzip-size "5.1.1" + immer "8.0.1" + is-root "2.1.0" + loader-utils "2.0.0" + open "^7.0.2" + pkg-up "3.1.0" + prompts "2.4.0" + react-error-overlay "^6.0.9" + recursive-readdir "2.2.2" + shell-quote "1.7.2" + strip-ansi "6.0.0" + text-table "0.2.0" + +react-dom@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-error-overlay@^6.0.9: + 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-is@^16.8.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-refresh@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" + integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== + +react-scripts@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-4.0.3.tgz#b1cafed7c3fa603e7628ba0f187787964cb5d345" + integrity sha512-S5eO4vjUzUisvkIPB7jVsKtuH2HhWcASREYWHAQ1FP5HyCv3xgn+wpILAEWkmy+A+tTNbSZClhxjT3qz6g4L1A== + dependencies: + "@babel/core" "7.12.3" + "@pmmmwh/react-refresh-webpack-plugin" "0.4.3" + "@svgr/webpack" "5.5.0" + "@typescript-eslint/eslint-plugin" "^4.5.0" + "@typescript-eslint/parser" "^4.5.0" + babel-eslint "^10.1.0" + babel-jest "^26.6.0" + babel-loader "8.1.0" + babel-plugin-named-asset-import "^0.3.7" + babel-preset-react-app "^10.0.0" + bfj "^7.0.2" + camelcase "^6.1.0" + case-sensitive-paths-webpack-plugin "2.3.0" + css-loader "4.3.0" + dotenv "8.2.0" + dotenv-expand "5.1.0" + eslint "^7.11.0" + eslint-config-react-app "^6.0.0" + eslint-plugin-flowtype "^5.2.0" + eslint-plugin-import "^2.22.1" + eslint-plugin-jest "^24.1.0" + eslint-plugin-jsx-a11y "^6.3.1" + eslint-plugin-react "^7.21.5" + eslint-plugin-react-hooks "^4.2.0" + eslint-plugin-testing-library "^3.9.2" + eslint-webpack-plugin "^2.5.2" + file-loader "6.1.1" + fs-extra "^9.0.1" + html-webpack-plugin "4.5.0" + identity-obj-proxy "3.0.0" + jest "26.6.0" + jest-circus "26.6.0" + jest-resolve "26.6.0" + jest-watch-typeahead "0.6.1" + mini-css-extract-plugin "0.11.3" + optimize-css-assets-webpack-plugin "5.0.4" + pnp-webpack-plugin "1.6.4" + postcss-flexbugs-fixes "4.2.1" + postcss-loader "3.0.0" + postcss-normalize "8.0.1" + postcss-preset-env "6.7.0" + postcss-safe-parser "5.0.2" + prompts "2.4.0" + react-app-polyfill "^2.0.0" + react-dev-utils "^11.0.3" + react-refresh "^0.8.3" + resolve "1.18.1" + resolve-url-loader "^3.1.2" + sass-loader "^10.0.5" + semver "7.3.2" + style-loader "1.3.0" + terser-webpack-plugin "4.2.3" + ts-pnp "1.2.0" + url-loader "4.1.1" + webpack "4.44.2" + webpack-dev-server "3.11.1" + webpack-manifest-plugin "2.2.0" + workbox-webpack-plugin "5.1.4" + optionalDependencies: + fsevents "^2.1.3" + +react@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, 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" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +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" + +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + 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== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regex-parser@^2.2.11: + version "2.2.11" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" + integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== + +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" + integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^3.0.1" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url-loader@^3.1.2: + version "3.1.4" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz#3c16caebe0b9faea9c7cc252fa49d2353c412320" + integrity sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg== + dependencies: + adjust-sourcemap-loader "3.0.0" + camelcase "5.3.1" + compose-function "3.0.3" + convert-source-map "1.7.0" + es6-iterator "2.0.3" + loader-utils "1.2.3" + postcss "7.0.36" + rework "1.0.1" + rework-visit "1.0.0" + source-map "0.6.1" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" + integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== + dependencies: + is-core-module "^2.0.0" + path-parse "^1.0.6" + +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.8.1: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rework-visit@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" + integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo= + +rework@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" + integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc= + dependencies: + convert-source-map "^0.3.3" + css "^2.0.0" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +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" + +rollup-plugin-babel@^4.3.3: + version "4.4.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz#d15bd259466a9d1accbdb2fe2fff17c52d030acb" + integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + rollup-pluginutils "^2.8.1" + +rollup-plugin-terser@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz#8c650062c22a8426c64268548957463bf981b413" + integrity sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w== + dependencies: + "@babel/code-frame" "^7.5.5" + jest-worker "^24.9.0" + rollup-pluginutils "^2.8.2" + serialize-javascript "^4.0.0" + terser "^4.6.2" + +rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: + version "2.8.2" + resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" + integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== + dependencies: + estree-walker "^0.6.1" + +rollup@^1.31.1: + version "1.32.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4" + integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A== + dependencies: + "@types/estree" "*" + "@types/node" "*" + acorn "^7.1.0" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +sanitize.css@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-10.0.0.tgz#b5cb2547e96d8629a60947544665243b1dc3657a" + integrity sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg== + +sass-loader@^10.0.5: + version "10.2.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.2.0.tgz#3d64c1590f911013b3fa48a0b22a83d5e1494716" + integrity sha512-kUceLzC1gIHz0zNJPpqRsJyisWatGYNFRmv2CKZK2/ngMJgLqxTbXwe/hJ85luyvZkgqU3VlJ33UVF2T/0g6mw== + dependencies: + klona "^2.0.4" + loader-utils "^2.0.0" + neo-async "^2.6.2" + schema-utils "^3.0.0" + semver "^7.3.2" + +sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5, schema-utils@^2.7.0, schema-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.8: + version "1.10.11" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" + integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA== + dependencies: + node-forge "^0.10.0" + +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + +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" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +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" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@1.7.2: + 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== + +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== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" + integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== + dependencies: + debug "^3.2.6" + eventsource "^1.0.7" + faye-websocket "^0.11.3" + inherits "^2.0.4" + json3 "^3.3.3" + url-parse "^1.5.3" + +sockjs@^0.3.21: + version "0.3.21" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" + integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + dependencies: + faye-websocket "^0.11.3" + uuid "^3.4.0" + websocket-driver "^0.7.4" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +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" + 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-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.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= + +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== + +sourcemap-codec@^1.4.4: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.10" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" + integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +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= + +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.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^2.0.2: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +stackframe@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" + integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "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= + +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@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-natural-compare@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" + integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== + +string-width@^3.0.0, string-width@^3.1.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.1.0, string-width@^4.2.0, string-width@^4.2.3: + 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.prototype.matchall@^4.0.5: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +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" + +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: + 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.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.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-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" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-comments@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d" + integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw== + dependencies: + babel-extract-comments "^1.0.0" + babel-plugin-transform-object-rest-spread "^6.26.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" + integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== + dependencies: + loader-utils "^2.0.0" + schema-utils "^2.7.0" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +svg-parser@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.0.0, svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +table@^6.0.9: + version "6.7.2" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.2.tgz#a8d39b9f5966693ca8b0feba270a78722cbaf3b0" + integrity sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g== + dependencies: + ajv "^8.0.1" + lodash.clonedeep "^4.5.0" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +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== + +tar@^6.0.2: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +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= + +tempy@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.3.0.tgz#6f6c5b295695a16130996ad5ab01a8bd726e8bf8" + integrity sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ== + dependencies: + temp-dir "^1.0.0" + type-fest "^0.3.1" + unique-string "^1.0.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +terser-webpack-plugin@4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" + integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== + dependencies: + cacache "^15.0.5" + find-cache-dir "^3.3.1" + jest-worker "^26.5.0" + p-limit "^3.0.2" + schema-utils "^3.0.0" + serialize-javascript "^5.0.1" + source-map "^0.6.1" + terser "^5.3.4" + webpack-sources "^1.4.3" + +terser-webpack-plugin@^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@^4.1.2, terser@^4.6.2, terser@^4.6.3: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +terser@^5.3.4: + version "5.9.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351" + integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + 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" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +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= + +throat@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +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" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tmpl@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +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== + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +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-pnp@1.2.0, ts-pnp@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" + integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== + +tsconfig-paths@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" + integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tsutils@^3.17.1, tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + 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" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" + integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" + integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@^4.2.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== + +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" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + 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" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= + dependencies: + crypto-random-string "^1.0.0" + +universalify@^0.1.0, universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +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.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1, upath@^1.1.2, upath@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@4.1.1: + 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@^1.4.3, url-parse@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + 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@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +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== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watchpack-chokidar2@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== + dependencies: + chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== + dependencies: + graceful-fs "^4.1.2" + neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.1" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webpack-dev-middleware@^3.7.2: + 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-dev-server@3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz#c74028bf5ba8885aaf230e48a20e8936ab8511f0" + integrity sha512-u4R3mRzZkbxQVa+MBWi2uVpB5W59H3ekZAJsQlKUTdl7Elcah2EhygTPLmeFXybQkf9i2+L0kn7ik9SnXa6ihQ== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.3.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.8" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.26" + schema-utils "^1.0.0" + selfsigned "^1.10.8" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + sockjs-client "^1.5.0" + spdy "^4.0.2" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "^13.3.2" + +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-manifest-plugin@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz#19ca69b435b0baec7e29fbe90fb4015de2de4f16" + integrity sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ== + dependencies: + fs-extra "^7.0.0" + lodash ">=3.5 <5" + object.entries "^1.1.0" + tapable "^1.0.0" + +webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@4.44.2: + version "4.44.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" + integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== + 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.3.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" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +workbox-background-sync@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz#5ae0bbd455f4e9c319e8d827c055bb86c894fd12" + integrity sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA== + dependencies: + workbox-core "^5.1.4" + +workbox-broadcast-update@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz#0eeb89170ddca7f6914fa3523fb14462891f2cfc" + integrity sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA== + dependencies: + workbox-core "^5.1.4" + +workbox-build@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-5.1.4.tgz#23d17ed5c32060c363030c8823b39d0eabf4c8c7" + integrity sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow== + dependencies: + "@babel/core" "^7.8.4" + "@babel/preset-env" "^7.8.4" + "@babel/runtime" "^7.8.4" + "@hapi/joi" "^15.1.0" + "@rollup/plugin-node-resolve" "^7.1.1" + "@rollup/plugin-replace" "^2.3.1" + "@surma/rollup-plugin-off-main-thread" "^1.1.1" + common-tags "^1.8.0" + fast-json-stable-stringify "^2.1.0" + fs-extra "^8.1.0" + glob "^7.1.6" + lodash.template "^4.5.0" + pretty-bytes "^5.3.0" + rollup "^1.31.1" + rollup-plugin-babel "^4.3.3" + rollup-plugin-terser "^5.3.1" + source-map "^0.7.3" + source-map-url "^0.4.0" + stringify-object "^3.3.0" + strip-comments "^1.0.2" + tempy "^0.3.0" + upath "^1.2.0" + workbox-background-sync "^5.1.4" + workbox-broadcast-update "^5.1.4" + workbox-cacheable-response "^5.1.4" + workbox-core "^5.1.4" + workbox-expiration "^5.1.4" + workbox-google-analytics "^5.1.4" + workbox-navigation-preload "^5.1.4" + workbox-precaching "^5.1.4" + workbox-range-requests "^5.1.4" + workbox-routing "^5.1.4" + workbox-strategies "^5.1.4" + workbox-streams "^5.1.4" + workbox-sw "^5.1.4" + workbox-window "^5.1.4" + +workbox-cacheable-response@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz#9ff26e1366214bdd05cf5a43da9305b274078a54" + integrity sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA== + dependencies: + workbox-core "^5.1.4" + +workbox-core@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-5.1.4.tgz#8bbfb2362ecdff30e25d123c82c79ac65d9264f4" + integrity sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg== + +workbox-expiration@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-5.1.4.tgz#92b5df461e8126114943a3b15c55e4ecb920b163" + integrity sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ== + dependencies: + workbox-core "^5.1.4" + +workbox-google-analytics@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz#b3376806b1ac7d7df8418304d379707195fa8517" + integrity sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA== + dependencies: + workbox-background-sync "^5.1.4" + workbox-core "^5.1.4" + workbox-routing "^5.1.4" + workbox-strategies "^5.1.4" + +workbox-navigation-preload@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz#30d1b720d26a05efc5fa11503e5cc1ed5a78902a" + integrity sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ== + dependencies: + workbox-core "^5.1.4" + +workbox-precaching@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-5.1.4.tgz#874f7ebdd750dd3e04249efae9a1b3f48285fe6b" + integrity sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA== + dependencies: + workbox-core "^5.1.4" + +workbox-range-requests@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz#7066a12c121df65bf76fdf2b0868016aa2bab859" + integrity sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw== + dependencies: + workbox-core "^5.1.4" + +workbox-routing@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-5.1.4.tgz#3e8cd86bd3b6573488d1a2ce7385e547b547e970" + integrity sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw== + dependencies: + workbox-core "^5.1.4" + +workbox-strategies@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-5.1.4.tgz#96b1418ccdfde5354612914964074d466c52d08c" + integrity sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA== + dependencies: + workbox-core "^5.1.4" + workbox-routing "^5.1.4" + +workbox-streams@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-5.1.4.tgz#05754e5e3667bdc078df2c9315b3f41210d8cac0" + integrity sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw== + dependencies: + workbox-core "^5.1.4" + workbox-routing "^5.1.4" + +workbox-sw@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-5.1.4.tgz#2bb34c9f7381f90d84cef644816d45150011d3db" + integrity sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA== + +workbox-webpack-plugin@5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz#7bfe8c16e40fe9ed8937080ac7ae9c8bde01e79c" + integrity sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ== + dependencies: + "@babel/runtime" "^7.5.5" + fast-json-stable-stringify "^2.0.0" + source-map-url "^0.4.0" + upath "^1.1.2" + webpack-sources "^1.3.0" + workbox-build "^5.1.4" + +workbox-window@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-5.1.4.tgz#2740f7dea7f93b99326179a62f1cc0ca2c93c863" + integrity sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw== + dependencies: + workbox-core "^5.1.4" + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +worker-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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +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" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +ws@^7.4.6: + version "7.5.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0, yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/npm/react/examples/react-scripts/cypress.config.js b/npm/react/examples/react-scripts/cypress.config.js new file mode 100644 index 0000000000..684c8b356a --- /dev/null +++ b/npm/react/examples/react-scripts/cypress.config.js @@ -0,0 +1,12 @@ +const { defineConfig } = require('cypress') +const { devServer } = require('@cypress/react/plugins/react-scripts') + +module.exports = defineConfig({ + 'video': false, + 'viewportWidth': 500, + 'viewportHeight': 800, + 'experimentalFetchPolyfill': true, + 'component': { + devServer, + }, +}) diff --git a/npm/react/examples/react-scripts/cypress.json b/npm/react/examples/react-scripts/cypress.json deleted file mode 100644 index 6c8427ea33..0000000000 --- a/npm/react/examples/react-scripts/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 800, - "experimentalFetchPolyfill": true, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/react-scripts-typescript/cypress/integration/cy-spec.js b/npm/react/examples/react-scripts/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/react-scripts-typescript/cypress/integration/cy-spec.js rename to npm/react/examples/react-scripts/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/react-scripts/cypress/plugins/index.js b/npm/react/examples/react-scripts/cypress/plugins/index.js deleted file mode 100644 index df575d3a87..0000000000 --- a/npm/react/examples/react-scripts/cypress/plugins/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config, {}) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/react-scripts/cypress/support/component-index.html b/npm/react/examples/react-scripts/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/react-scripts/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/react-scripts/cypress/support/index.js b/npm/react/examples/react-scripts/cypress/support/component.js similarity index 100% rename from npm/react/examples/react-scripts/cypress/support/index.js rename to npm/react/examples/react-scripts/cypress/support/component.js diff --git a/npm/react/examples/react-scripts/package.json b/npm/react/examples/react-scripts/package.json index f8c96a38e8..a8ceb5497c 100644 --- a/npm/react/examples/react-scripts/package.json +++ b/npm/react/examples/react-scripts/package.json @@ -4,10 +4,10 @@ "private": true, "scripts": { "check-coverage": "check-coverage src/App.js src/calc.js src/Child.js src/services.js src/RemotePizza.js cypress/fixtures/add.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered src/App.js src/calc.js src/Child.js src/services.js src/RemotePizza.js cypress/fixtures/add.js", "start": "react-scripts start", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/react-scripts/src/App.cy-spec.js b/npm/react/examples/react-scripts/src/App.cy.js similarity index 100% rename from npm/react/examples/react-scripts/src/App.cy-spec.js rename to npm/react/examples/react-scripts/src/App.cy.js diff --git a/npm/react/examples/react-scripts/src/Logo.cy-spec.js b/npm/react/examples/react-scripts/src/Logo.cy.js similarity index 100% rename from npm/react/examples/react-scripts/src/Logo.cy-spec.js rename to npm/react/examples/react-scripts/src/Logo.cy.js diff --git a/npm/react/examples/react-scripts/src/RemotePizza.cy-spec.js b/npm/react/examples/react-scripts/src/RemotePizza.cy.js similarity index 100% rename from npm/react/examples/react-scripts/src/RemotePizza.cy-spec.js rename to npm/react/examples/react-scripts/src/RemotePizza.cy.js diff --git a/npm/react/examples/react-scripts/src/fixture.cy-spec.js b/npm/react/examples/react-scripts/src/fixture.cy.js similarity index 100% rename from npm/react/examples/react-scripts/src/fixture.cy-spec.js rename to npm/react/examples/react-scripts/src/fixture.cy.js diff --git a/npm/react/examples/react-scripts/src/resources.cy-spec.js b/npm/react/examples/react-scripts/src/resources.cy.js similarity index 100% rename from npm/react/examples/react-scripts/src/resources.cy-spec.js rename to npm/react/examples/react-scripts/src/resources.cy.js diff --git a/npm/react/examples/sass-and-ts/cypress.config.js b/npm/react/examples/sass-and-ts/cypress.config.js new file mode 100644 index 0000000000..17b2fd7272 --- /dev/null +++ b/npm/react/examples/sass-and-ts/cypress.config.js @@ -0,0 +1,24 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'env': { + 'coverage': true, + }, + 'component': { + setupNodeEvents (on, config) { + // load Webpack file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/load-webpack') + + devServer(on, config, { + webpackFilename: 'webpack.config.js', + }) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} diff --git a/npm/react/examples/sass-and-ts/cypress.json b/npm/react/examples/sass-and-ts/cypress.json deleted file mode 100644 index 1341d16e3b..0000000000 --- a/npm/react/examples/sass-and-ts/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.*", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src", - "nodeVersion": "system", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/react-scripts/cypress/integration/cy-spec.js b/npm/react/examples/sass-and-ts/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/react-scripts/cypress/integration/cy-spec.js rename to npm/react/examples/sass-and-ts/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/sass-and-ts/cypress/plugins/index.js b/npm/react/examples/sass-and-ts/cypress/plugins/index.js deleted file mode 100644 index 0473ac85b7..0000000000 --- a/npm/react/examples/sass-and-ts/cypress/plugins/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// @ts-check - -// load Webpack file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/load-webpack') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config, { - webpackFilename: 'webpack.config.js', - }) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/sass-and-ts/cypress/support/component-index.html b/npm/react/examples/sass-and-ts/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/sass-and-ts/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/system-tests/projects/webpack-dev-server/cypress/support/component.js b/npm/react/examples/sass-and-ts/cypress/support/component.js similarity index 100% rename from system-tests/projects/webpack-dev-server/cypress/support/component.js rename to npm/react/examples/sass-and-ts/cypress/support/component.js diff --git a/npm/react/examples/sass-and-ts/package.json b/npm/react/examples/sass-and-ts/package.json index 99e3e3ab2d..9f66e35c91 100644 --- a/npm/react/examples/sass-and-ts/package.json +++ b/npm/react/examples/sass-and-ts/package.json @@ -4,9 +4,9 @@ "private": true, "scripts": { "check-coverage": "check-coverage src/App.tsx", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered src/App.tsx", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "dependencies": { "sass-loader": "10.0.2" @@ -15,6 +15,6 @@ "@cypress/react": "file:../../dist", "mocha-junit-reporter": "^2.0.0", "mocha-multi-reporters": "^1.5.1", - "sass": "1.32.0" + "sass": "1.44.0" } } diff --git a/npm/react/examples/sass-and-ts/src/App.spec.tsx b/npm/react/examples/sass-and-ts/src/App.cy.tsx similarity index 100% rename from npm/react/examples/sass-and-ts/src/App.spec.tsx rename to npm/react/examples/sass-and-ts/src/App.cy.tsx diff --git a/npm/react/examples/snapshots/cypress.config.js b/npm/react/examples/snapshots/cypress.config.js new file mode 100644 index 0000000000..5cac5fb09b --- /dev/null +++ b/npm/react/examples/snapshots/cypress.config.js @@ -0,0 +1,32 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'env': { + 'cypress-plugin-snapshots': { + 'prettier': true, + }, + }, + 'component': { + 'excludeSpecPattern': [ + '**/__snapshots__/*', + '**/__image_snapshots__/*', + ], + setupNodeEvents (on, config) { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/react-scripts') + const { initPlugin: initSnapshots } = require('cypress-plugin-snapshots/plugin') + + devServer(on, config) + // initialize the snapshots plugin following + // https://github.com/meinaart/cypress-plugin-snapshots + initSnapshots(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} diff --git a/npm/react/examples/snapshots/cypress.json b/npm/react/examples/snapshots/cypress.json deleted file mode 100644 index 4abcd4d5d3..0000000000 --- a/npm/react/examples/snapshots/cypress.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "env": { - "cypress-plugin-snapshots": { - "prettier": true - } - } -} \ No newline at end of file diff --git a/npm/react/examples/snapshots/cypress/component/PositiveCounter-spec.js b/npm/react/examples/snapshots/cypress/component/PositiveCounter.cy.js similarity index 100% rename from npm/react/examples/snapshots/cypress/component/PositiveCounter-spec.js rename to npm/react/examples/snapshots/cypress/component/PositiveCounter.cy.js diff --git a/npm/react/examples/sass-and-ts/cypress/integration/cy-spec.js b/npm/react/examples/snapshots/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/sass-and-ts/cypress/integration/cy-spec.js rename to npm/react/examples/snapshots/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/snapshots/cypress/plugins/index.js b/npm/react/examples/snapshots/cypress/plugins/index.js deleted file mode 100644 index 16343ddc2c..0000000000 --- a/npm/react/examples/snapshots/cypress/plugins/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') -const { initPlugin: initSnapshots } = require('cypress-plugin-snapshots/plugin') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - // initialize the snapshots plugin following - // https://github.com/meinaart/cypress-plugin-snapshots - initSnapshots(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/snapshots/cypress/support/component-index.html b/npm/react/examples/snapshots/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/snapshots/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/snapshots/cypress/support/index.js b/npm/react/examples/snapshots/cypress/support/component.js similarity index 100% rename from npm/react/examples/snapshots/cypress/support/index.js rename to npm/react/examples/snapshots/cypress/support/component.js diff --git a/npm/react/examples/snapshots/package.json b/npm/react/examples/snapshots/package.json index 94b5ccbf44..ff0fe9fa25 100644 --- a/npm/react/examples/snapshots/package.json +++ b/npm/react/examples/snapshots/package.json @@ -4,9 +4,9 @@ "private": true, "scripts": { "check-coverage": "check-coverage src/App.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered src/App.js", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/tailwind/README.md b/npm/react/examples/tailwind/README.md deleted file mode 100644 index 4546887f42..0000000000 --- a/npm/react/examples/tailwind/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# example: tailwind - -> Component testing when using [Tailwind CSS](https://tailwindcss.com/), example created following the blog post [Using Tailwind CSS With React](https://medium.com/codingthesmartway-com-blog/using-tailwind-css-with-react-ced163d0e9e9) and Tailwind's own documentation. - -## Usage - -1. Make sure the root project has been built . - -```bash -# in the root of the project -npm install -npm run build -``` - -2. Run `npm install` in this folder to symlink the `@cypress/react` dependency. - -```bash -# in this folder -npm install -``` - -3. Start Cypress - -```bash -npm run cy:open -# or just run headless tests -npm test -``` - -## Run tests - -You can execute `npm run build:css` to let Tailwind generate `src/styles/main.generated.css` or run Cypress, since this step is set as a pre-test step inside [package.json](package.json). - -```shell -npm run cy:open -# or just run headless tests -npm test -``` - -## Tests - -- [src/App.cy-spec.js](src/App.cy-spec.js) tests component [src/App.js](src/App.js) that uses Tailwind style bundle `src/styles/main.generated.css` - -![Tailwind test](./images/tailwind.png) - -- [src/playground.cy-spec.js](src/playground.cy-spec.js) imports the CSS directly and shows off different available classes, allowing you to experiment with them from the test - -![Playground](images/playground.png) - -Note: each test uses [cy.screenshot](https://on.cypress.io/screenshot) at the end to save an image to `cypress/screenshots` folder. - -## See also - -When working with styles, we recommend [visual testing](https://on.cypress.io/visual-testing) using one of 3rd party [visual plugins](https://on.cypress.io/plugins#visual-testing). See a few visual testing examples in this repository. diff --git a/npm/react/examples/tailwind/cypress.json b/npm/react/examples/tailwind/cypress.json deleted file mode 100644 index b3055fbcbb..0000000000 --- a/npm/react/examples/tailwind/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src", - "env": { - "coverage": true - } -} \ No newline at end of file diff --git a/npm/react/examples/tailwind/cypress/plugins/index.js b/npm/react/examples/tailwind/cypress/plugins/index.js deleted file mode 100644 index 33bce3362b..0000000000 --- a/npm/react/examples/tailwind/cypress/plugins/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/tailwind/cypress/support/index.js b/npm/react/examples/tailwind/cypress/support/index.js deleted file mode 100644 index d02d8a05f8..0000000000 --- a/npm/react/examples/tailwind/cypress/support/index.js +++ /dev/null @@ -1 +0,0 @@ -require('@cypress/code-coverage/support') diff --git a/npm/react/examples/tailwind/images/playground.png b/npm/react/examples/tailwind/images/playground.png deleted file mode 100644 index c034467b8f..0000000000 Binary files a/npm/react/examples/tailwind/images/playground.png and /dev/null differ diff --git a/npm/react/examples/tailwind/images/tailwind.png b/npm/react/examples/tailwind/images/tailwind.png deleted file mode 100644 index d2027183ac..0000000000 Binary files a/npm/react/examples/tailwind/images/tailwind.png and /dev/null differ diff --git a/npm/react/examples/tailwind/package.json b/npm/react/examples/tailwind/package.json deleted file mode 100644 index 0695dfeb2d..0000000000 --- a/npm/react/examples/tailwind/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "example-tailwind", - "description": "Component testing with Tailwind CSS", - "private": true, - "scripts": { - "build:css": "tailwindcss build src/styles/tailwind.css -o src/styles/main.generated.css", - "precy:open": "npm run build:css", - "cy:open": "node ../../../../scripts/cypress open-ct", - "pretest": "npm run build:css", - "test": "node ../../../../scripts/cypress run-ct" - }, - "devDependencies": { - "@cypress/react": "file:../../dist", - "mocha-junit-reporter": "^2.0.0", - "mocha-multi-reporters": "^1.5.1", - "tailwindcss": "1.4.6" - } -} diff --git a/npm/react/examples/tailwind/src/App.cy-spec.js b/npm/react/examples/tailwind/src/App.cy-spec.js deleted file mode 100644 index 76d5f0d437..0000000000 --- a/npm/react/examples/tailwind/src/App.cy-spec.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -import React from 'react' -import { mount } from '@cypress/react' -import App from './App' - -describe('Tailwind App', () => { - it('is stylish', () => { - mount() - // it has expected colors and styles - cy.get('h1.font-bold').should('have.css', 'font-weight', '700') - cy.get('button.text-white') - .should('have.css', 'color', 'rgb(255, 255, 255)') - .and('have.class', 'rounded') - - cy.log('confirm rounded corners') - cy.get('button.rounded').should(($el) => { - expect($el.css('border-radius')).to.match(/^\d+px$/) - }) - - cy.screenshot() - }) -}) diff --git a/npm/react/examples/tailwind/src/App.js b/npm/react/examples/tailwind/src/App.js deleted file mode 100644 index 83cba5133c..0000000000 --- a/npm/react/examples/tailwind/src/App.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react' -import './styles/main.generated.css' - -function App () { - return ( -
-
-

Tailwind CSS Demo

-
-
-

Have much fun using Tailwind CSS

- -
-
- ) -} -export default App diff --git a/npm/react/examples/tailwind/src/playground.cy-spec.js b/npm/react/examples/tailwind/src/playground.cy-spec.js deleted file mode 100644 index 72f9990200..0000000000 --- a/npm/react/examples/tailwind/src/playground.cy-spec.js +++ /dev/null @@ -1,28 +0,0 @@ -// you can import CSS directly to experiment with component styles -import './styles/main.generated.css' -import React from 'react' -import { mount } from '@cypress/react' - -describe('Different styles', () => { - it('shows button styles', () => { - mount( -
-

We got buttons

- - - - - -
, - ) - - cy.get('button').should('have.length', 3) - cy.screenshot() - }) -}) diff --git a/npm/react/examples/tailwind/src/styles/tailwind.css b/npm/react/examples/tailwind/src/styles/tailwind.css deleted file mode 100644 index b5c61c9567..0000000000 --- a/npm/react/examples/tailwind/src/styles/tailwind.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/npm/react/examples/tailwind/yarn.lock b/npm/react/examples/tailwind/yarn.lock deleted file mode 100644 index d20da5d4fd..0000000000 --- a/npm/react/examples/tailwind/yarn.lock +++ /dev/null @@ -1,627 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@cypress/react@file:../../dist": - version "0.0.0" - -"@fullhuman/postcss-purgecss@^2.1.2": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz#50a954757ec78696615d3e118e3fee2d9291882e" - integrity sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw== - dependencies: - postcss "7.0.32" - purgecss "^2.3.0" - -"@oozcitak/dom@1.15.8": - version "1.15.8" - resolved "https://registry.yarnpkg.com/@oozcitak/dom/-/dom-1.15.8.tgz#0c0c7bb54cfdaadc07fd637913e706101721d15d" - integrity sha512-MoOnLBNsF+ok0HjpAvxYxR4piUhRDCEWK0ot3upwOOHYudJd30j6M+LNcE8RKpwfnclAX9T66nXXzkytd29XSw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/url" "1.0.4" - "@oozcitak/util" "8.3.8" - -"@oozcitak/infra@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@oozcitak/infra/-/infra-1.0.8.tgz#b0b089421f7d0f6878687608301fbaba837a7d17" - integrity sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg== - dependencies: - "@oozcitak/util" "8.3.8" - -"@oozcitak/url@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@oozcitak/url/-/url-1.0.4.tgz#ca8b1c876319cf5a648dfa1123600a6aa5cda6ba" - integrity sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - -"@oozcitak/util@8.3.8": - version "8.3.8" - resolved "https://registry.yarnpkg.com/@oozcitak/util/-/util-8.3.8.tgz#10f65fe1891fd8cde4957360835e78fd1936bfdd" - integrity sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ== - -"@types/node@14.6.2": - version "14.6.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f" - integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A== - -acorn-node@^1.6.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - -acorn-walk@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn@^7.0.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -autoprefixer@^9.4.5: - 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" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -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" - -browserslist@^4.12.0: - version "4.14.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.5.tgz#1c751461a102ddc60e40993639b709be7f2c4015" - integrity sha512-Z+vsCZIvCBvqLoYkBFTwEYH3v5MCQbsAjp50ERycpOjnPmolg1Gjy4+KaWWpm8QOJt9GHkhdqAl14NpCX73CWA== - dependencies: - caniuse-lite "^1.0.30001135" - electron-to-chromium "^1.3.571" - escalade "^3.1.0" - node-releases "^1.1.61" - -bytes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -camelcase-css@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - -caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001135: - version "1.0.30001146" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz#c61fcb1474520c1462913689201fb292ba6f447c" - integrity sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug== - -chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" - integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -colorette@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" - integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== - -commander@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - -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= - -css-unit-converter@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21" - integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cypress-circleci-reporter@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cypress-circleci-reporter/-/cypress-circleci-reporter-0.2.0.tgz#a3e1571694f4e21649a6af4d508e68948d23622d" - integrity sha512-uhqcJwvtKJ7Bw3RHVBTqUH9GP2L6jq+qLp/+/Jh3/OSe5Af6H7RxIARhvawsvbPrg9lMWdW/jCezjeUcXrl9uA== - dependencies: - strip-ansi "^6.0.0" - xmlbuilder2 "^2.1.1" - -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= - -detective@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" - integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== - dependencies: - acorn-node "^1.6.1" - defined "^1.0.0" - minimist "^1.1.1" - -electron-to-chromium@^1.3.571: - version "1.3.578" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.578.tgz#e6671936f4571a874eb26e2e833aa0b2c0b776e0" - integrity sha512-z4gU6dA1CbBJsAErW5swTGAaU2TBzc2mPAonJb00zqW1rOraDo2zfBMDRvaz9cVic+0JEZiYbHWPw/fTaZlG2Q== - -escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== - -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= - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -fs-extra@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -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= - -glob@^7.0.0, glob@^7.1.2: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - 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" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -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: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -lodash.toarray@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" - integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= - -lodash@^4.17.15: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -node-emoji@^1.8.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" - integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== - dependencies: - lodash.toarray "^4.4.0" - -node-releases@^1.1.61: - version "1.1.61" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" - integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== - -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.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== - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -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= - -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= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -postcss-functions@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e" - integrity sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4= - dependencies: - glob "^7.1.2" - object-assign "^4.1.1" - postcss "^6.0.9" - postcss-value-parser "^3.3.0" - -postcss-js@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-2.0.3.tgz#a96f0f23ff3d08cec7dc5b11bf11c5f8077cdab9" - integrity sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w== - dependencies: - camelcase-css "^2.0.1" - postcss "^7.0.18" - -postcss-nested@^4.1.1: - version "4.2.3" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-4.2.3.tgz#c6f255b0a720549776d220d00c4b70cd244136f6" - integrity sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw== - dependencies: - postcss "^7.0.32" - postcss-selector-parser "^6.0.2" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" - integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - util-deprecate "^1.0.2" - -postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -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.32: - version "7.0.32" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" - integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^6.0.9: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.11, postcss@^7.0.18, postcss@^7.0.32: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -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= - -purgecss@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-2.3.0.tgz#5327587abf5795e6541517af8b190a6fb5488bb3" - integrity sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ== - dependencies: - commander "^5.0.0" - glob "^7.0.0" - postcss "7.0.32" - postcss-selector-parser "^6.0.2" - -reduce-css-calc@^2.1.6: - version "2.1.7" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.7.tgz#1ace2e02c286d78abcd01fd92bfe8097ab0602c2" - integrity sha512-fDnlZ+AybAS3C7Q9xDq5y8A2z+lT63zLbynew/lur/IR24OQF5x98tfNwf79mzEdfywZ0a2wpM860FhFfMxZlA== - dependencies: - css-unit-converter "^1.1.1" - postcss-value-parser "^3.3.0" - -resolve@^1.14.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -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= - -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" - -supports-color@^5.3.0, supports-color@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -tailwindcss@1.4.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-1.4.6.tgz#17b37166ccda08d7e7f9ca995ea48ce1e0089700" - integrity sha512-qV0qInUq1FWih39Bc5CWECdgObSzRrbjGD4ke4kAPSIq6WXrPhv0wwOcUWJgJ66ltT9j+XnSRYikG8WNRU/fTQ== - dependencies: - "@fullhuman/postcss-purgecss" "^2.1.2" - autoprefixer "^9.4.5" - browserslist "^4.12.0" - bytes "^3.0.0" - chalk "^4.0.0" - color "^3.1.2" - detective "^5.2.0" - fs-extra "^8.0.0" - lodash "^4.17.15" - node-emoji "^1.8.1" - normalize.css "^8.0.1" - postcss "^7.0.11" - postcss-functions "^3.0.0" - postcss-js "^2.0.0" - postcss-nested "^4.1.1" - postcss-selector-parser "^6.0.0" - pretty-hrtime "^1.0.3" - reduce-css-calc "^2.1.6" - resolve "^1.14.2" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -xmlbuilder2@^2.1.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/xmlbuilder2/-/xmlbuilder2-2.4.0.tgz#fb6c5171bef1bcb984c88cfef5210e17b7b841cd" - integrity sha512-KrOVUGD65xTQ7ZA+GMQGdBSpe1Ufu5ylCQSYVk6QostySDkxPmAQ0WWIu7dR3JjLfVbF22RFQX7KyrZ6VTLcQg== - dependencies: - "@oozcitak/dom" "1.15.8" - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - "@types/node" "14.6.2" - js-yaml "3.14.0" - -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/npm/react/examples/using-babel-typescript/cypress.config.js b/npm/react/examples/using-babel-typescript/cypress.config.js new file mode 100644 index 0000000000..13ecfbe1db --- /dev/null +++ b/npm/react/examples/using-babel-typescript/cypress.config.js @@ -0,0 +1,14 @@ +const { devServer } = require('@cypress/react/plugins/babel') + +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'component': { + // let's bundle spec files and the components they include using + // the same bundling settings as the project by loading .babelrc + // https://github.com/bahmutov/cypress-react-unit-test#install + devServer, + }, +} diff --git a/npm/react/examples/using-babel-typescript/cypress.json b/npm/react/examples/using-babel-typescript/cypress.json deleted file mode 100644 index 86ef45a150..0000000000 --- a/npm/react/examples/using-babel-typescript/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.tsx", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/snapshots/cypress/integration/cy-spec.js b/npm/react/examples/using-babel-typescript/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/snapshots/cypress/integration/cy-spec.js rename to npm/react/examples/using-babel-typescript/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/using-babel-typescript/cypress/plugins/index.js b/npm/react/examples/using-babel-typescript/cypress/plugins/index.js deleted file mode 100644 index be2d6bc32f..0000000000 --- a/npm/react/examples/using-babel-typescript/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// @ts-check - -// let's bundle spec files and the components they include using -// the same bundling settings as the project by loading .babelrc -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/babel') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/using-babel-typescript/cypress/support/component-index.html b/npm/react/examples/using-babel-typescript/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/using-babel-typescript/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/sass-and-ts/cypress/support/index.js b/npm/react/examples/using-babel-typescript/cypress/support/component.js similarity index 100% rename from npm/react/examples/sass-and-ts/cypress/support/index.js rename to npm/react/examples/using-babel-typescript/cypress/support/component.js diff --git a/npm/react/examples/using-babel-typescript/package.json b/npm/react/examples/using-babel-typescript/package.json index fd8424d068..9ec3b14722 100644 --- a/npm/react/examples/using-babel-typescript/package.json +++ b/npm/react/examples/using-babel-typescript/package.json @@ -3,8 +3,8 @@ "description": "Component testing for TypeScript projects using Babel config", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@babel/core": "7.4.5", diff --git a/npm/react/examples/using-babel-typescript/src/Component.spec.tsx b/npm/react/examples/using-babel-typescript/src/Component.cy.tsx similarity index 100% rename from npm/react/examples/using-babel-typescript/src/Component.spec.tsx rename to npm/react/examples/using-babel-typescript/src/Component.cy.tsx diff --git a/npm/react/examples/using-babel/cypress.config.js b/npm/react/examples/using-babel/cypress.config.js new file mode 100644 index 0000000000..be5de6927d --- /dev/null +++ b/npm/react/examples/using-babel/cypress.config.js @@ -0,0 +1,20 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'component': { + setupNodeEvents (on, config) { + // let's bundle spec files and the components they include using + // the same bundling settings as the project by loading .babelrc + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/babel') + + devServer(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} diff --git a/npm/react/examples/using-babel/cypress.json b/npm/react/examples/using-babel/cypress.json deleted file mode 100644 index f97af0417f..0000000000 --- a/npm/react/examples/using-babel/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/tailwind/cypress/integration/cy-spec.js b/npm/react/examples/using-babel/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/tailwind/cypress/integration/cy-spec.js rename to npm/react/examples/using-babel/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/using-babel/cypress/plugins/index.js b/npm/react/examples/using-babel/cypress/plugins/index.js deleted file mode 100644 index 300010f49a..0000000000 --- a/npm/react/examples/using-babel/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// @ts-check - -// let's bundle spec files and the components they include using -// the same bundling settings as the project by loading .babelrc -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/babel') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/using-babel/cypress/support/component-index.html b/npm/react/examples/using-babel/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/using-babel/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/using-babel-typescript/cypress/support/index.js b/npm/react/examples/using-babel/cypress/support/component.js similarity index 100% rename from npm/react/examples/using-babel-typescript/cypress/support/index.js rename to npm/react/examples/using-babel/cypress/support/component.js diff --git a/npm/react/examples/using-babel/package.json b/npm/react/examples/using-babel/package.json index 2ce2addcd9..a364397727 100644 --- a/npm/react/examples/using-babel/package.json +++ b/npm/react/examples/using-babel/package.json @@ -3,8 +3,8 @@ "description": "Component testing for projects using Babel config", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@babel/core": "7.4.5", diff --git a/npm/react/examples/using-babel/src/Component.spec.js b/npm/react/examples/using-babel/src/Component.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/Component.spec.js rename to npm/react/examples/using-babel/src/Component.cy.js diff --git a/npm/react/examples/using-babel/src/ComponentReq.spec.js b/npm/react/examples/using-babel/src/ComponentReq.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/ComponentReq.spec.js rename to npm/react/examples/using-babel/src/ComponentReq.cy.js diff --git a/npm/react/examples/using-babel/src/Mock.spec.js b/npm/react/examples/using-babel/src/Mock.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/Mock.spec.js rename to npm/react/examples/using-babel/src/Mock.cy.js diff --git a/npm/react/examples/using-babel/src/Post.spec.js b/npm/react/examples/using-babel/src/Post.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/Post.spec.js rename to npm/react/examples/using-babel/src/Post.cy.js diff --git a/npm/react/examples/using-babel/src/Skeleton.spec.js b/npm/react/examples/using-babel/src/Skeleton.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/Skeleton.spec.js rename to npm/react/examples/using-babel/src/Skeleton.cy.js diff --git a/npm/react/examples/using-babel/src/plain.spec.js b/npm/react/examples/using-babel/src/plain.cy.js similarity index 100% rename from npm/react/examples/using-babel/src/plain.spec.js rename to npm/react/examples/using-babel/src/plain.cy.js diff --git a/npm/react/examples/visual-sudoku/cypress.config.js b/npm/react/examples/visual-sudoku/cypress.config.js new file mode 100644 index 0000000000..c9540c2518 --- /dev/null +++ b/npm/react/examples/visual-sudoku/cypress.config.js @@ -0,0 +1,21 @@ +module.exports = { + "video": false, + "fixturesFolder": false, + "viewportWidth": 1000, + "viewportHeight": 1000, + 'component': { + "specPattern": "src/**/*cy-spec.js", + setupNodeEvents(on, config) { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/react-scripts') + const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin') + + addMatchImageSnapshotPlugin(on, config) + devServer(on, config) + // IMPORTANT to return the config object + // with the any changed environment variables + return config + } + } +} diff --git a/npm/react/examples/visual-sudoku/cypress.json b/npm/react/examples/visual-sudoku/cypress.json deleted file mode 100644 index 561f83d47b..0000000000 --- a/npm/react/examples/visual-sudoku/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 1000, - "viewportHeight": 1000, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/using-babel-typescript/cypress/integration/spec.js b/npm/react/examples/visual-sudoku/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/using-babel-typescript/cypress/integration/spec.js rename to npm/react/examples/visual-sudoku/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/visual-sudoku/cypress/plugins/index.js b/npm/react/examples/visual-sudoku/cypress/plugins/index.js deleted file mode 100644 index c8f399ba98..0000000000 --- a/npm/react/examples/visual-sudoku/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') -const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - addMatchImageSnapshotPlugin(on, config) - devServer(on, config) - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/actions with modes.snap.png b/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/actions with modes.snap.png similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/actions with modes.snap.png rename to npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/actions with modes.snap.png diff --git a/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/actions.snap.png b/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/actions.snap.png similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/actions.snap.png rename to npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/actions.snap.png diff --git a/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/header.snap.png b/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/header.snap.png similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/header.snap.png rename to npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/header.snap.png diff --git a/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/numbers.snap.png b/npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/numbers.snap.png similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-spec.js/numbers.snap.png rename to npm/react/examples/visual-sudoku/cypress/snapshots/App.cy-cy.js/numbers.snap.png diff --git a/npm/react/examples/visual-sudoku/cypress/support/component-index.html b/npm/react/examples/visual-sudoku/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/visual-sudoku/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/visual-sudoku/cypress/support/index.js b/npm/react/examples/visual-sudoku/cypress/support/component.js similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/support/index.js rename to npm/react/examples/visual-sudoku/cypress/support/component.js diff --git a/npm/react/examples/visual-sudoku/package.json b/npm/react/examples/visual-sudoku/package.json index 03a4010ce7..a942efe779 100644 --- a/npm/react/examples/visual-sudoku/package.json +++ b/npm/react/examples/visual-sudoku/package.json @@ -6,11 +6,11 @@ "license": "MIT", "scripts": { "build": "react-scripts build", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "docker:run": "docker run -it -v $PWD/../..:/e2e -w /e2e/examples/visual-sudoku cypress/included:4.5.0", "eject": "react-scripts eject", "start": "react-scripts start", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "browserslist": { "production": [ diff --git a/npm/react/examples/visual-sudoku/src/App.cy-spec.js b/npm/react/examples/visual-sudoku/src/App.cy.js similarity index 100% rename from npm/react/examples/visual-sudoku/src/App.cy-spec.js rename to npm/react/examples/visual-sudoku/src/App.cy.js diff --git a/npm/react/examples/visual-testing-with-applitools/cypress.config.js b/npm/react/examples/visual-testing-with-applitools/cypress.config.js new file mode 100644 index 0000000000..3eb3590d5d --- /dev/null +++ b/npm/react/examples/visual-testing-with-applitools/cypress.config.js @@ -0,0 +1,24 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 1000, + 'viewportHeight': 1000, + 'env': { + 'coverage': false, + }, + 'component': { + setupNodeEvents (on, config) { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/react-scripts') + + devServer(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} + +require('@applitools/eyes-cypress')(module) diff --git a/npm/react/examples/visual-testing-with-applitools/cypress.json b/npm/react/examples/visual-testing-with-applitools/cypress.json deleted file mode 100644 index a86687662f..0000000000 --- a/npm/react/examples/visual-testing-with-applitools/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "viewportWidth": 1000, - "viewportHeight": 1000, - "componentFolder": "src", - "env": { - "coverage": false - } -} \ No newline at end of file diff --git a/npm/react/examples/using-babel/cypress/integration/spec.js b/npm/react/examples/visual-testing-with-applitools/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/using-babel/cypress/integration/spec.js rename to npm/react/examples/visual-testing-with-applitools/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/visual-testing-with-applitools/cypress/plugins/index.js b/npm/react/examples/visual-testing-with-applitools/cypress/plugins/index.js deleted file mode 100644 index 30d8e39b95..0000000000 --- a/npm/react/examples/visual-testing-with-applitools/cypress/plugins/index.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} - -// @ts-ignore -require('@applitools/eyes-cypress')(module) diff --git a/npm/react/examples/visual-testing-with-applitools/cypress/support/component-index.html b/npm/react/examples/visual-testing-with-applitools/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/visual-testing-with-applitools/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-applitools/cypress/support/index.js b/npm/react/examples/visual-testing-with-applitools/cypress/support/component.js similarity index 100% rename from npm/react/examples/visual-testing-with-applitools/cypress/support/index.js rename to npm/react/examples/visual-testing-with-applitools/cypress/support/component.js diff --git a/npm/react/examples/visual-testing-with-applitools/package.json b/npm/react/examples/visual-testing-with-applitools/package.json index b0ddaadd20..fc1d0f29ee 100644 --- a/npm/react/examples/visual-testing-with-applitools/package.json +++ b/npm/react/examples/visual-testing-with-applitools/package.json @@ -3,8 +3,8 @@ "description": "Visual diffing for component testing using Applittols", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@applitools/eyes-cypress": "3.14.0", diff --git a/npm/react/examples/visual-testing-with-applitools/src/Chart.cy.js b/npm/react/examples/visual-testing-with-applitools/src/Chart.cy.js new file mode 100644 index 0000000000..9452edc854 --- /dev/null +++ b/npm/react/examples/visual-testing-with-applitools/src/Chart.cy.js @@ -0,0 +1,29 @@ +/// +import React from 'react' +import { mount } from '@cypress/react' +import { CustomTheme } from './Chart' + +describe('Chart', () => { + it('shows the chart', () => { + // Applitools commands like "cy.eyes*" + // https://www.npmjs.com/package/@applitools/eyes-cypress + cy.eyesOpen({ + appName: '@cypress/react', + testName: 'Chart example', + browser: [ + { + width: Cypress.config('viewportWidth'), + height: Cypress.config('viewportHeight'), + name: 'firefox', + }, + ], + // ignore "cy.eyes*" commands when using "cypress open --component" + isDisabled: Cypress.config('isInteractive'), + }) + + mount() + + cy.eyesCheckWindow('Chart') + cy.eyesClose() + }) +}) diff --git a/npm/react/examples/visual-testing-with-applitools/src/Chart.spec.js b/npm/react/examples/visual-testing-with-applitools/src/Chart.spec.js deleted file mode 100644 index 64d2d39bd1..0000000000 --- a/npm/react/examples/visual-testing-with-applitools/src/Chart.spec.js +++ /dev/null @@ -1,29 +0,0 @@ -/// -import React from 'react' -import { mount } from '@cypress/react' -import { CustomTheme } from './Chart' - -describe('Chart', () => { - it('shows the chart', () => { - // Applitools commands like "cy.eyes*" - // https://www.npmjs.com/package/@applitools/eyes-cypress - cy.eyesOpen({ - appName: '@cypress/react', - testName: 'Chart example', - browser: [ - { - width: Cypress.config('viewportWidth'), - height: Cypress.config('viewportHeight'), - name: 'firefox', - }, - ], - // ignore "cy.eyes*" commands when using "cypress open-ct" - isDisabled: Cypress.config('isInteractive'), - }) - - mount() - - cy.eyesCheckWindow('Chart') - cy.eyesClose() - }) -}) diff --git a/npm/react/examples/visual-testing-with-happo/.happo.js b/npm/react/examples/visual-testing-with-happo/.happo.js index 60e799c22b..a05a232d5b 100644 --- a/npm/react/examples/visual-testing-with-happo/.happo.js +++ b/npm/react/examples/visual-testing-with-happo/.happo.js @@ -1,8 +1,8 @@ // https://docs.happo.io/docs/cypress const { RemoteBrowserTarget } = require('happo.io') -// use the same resolution as cypress.json -const cypressConfig = require('./cypress.json') +// use the same resolution as cypress.config.js +const cypressConfig = require('./cypress.config.js') const width = cypressConfig.viewportWidth || 1000 const height = cypressConfig.viewportHeight || 660 const viewport = `${width}x${height}` diff --git a/npm/react/examples/visual-testing-with-happo/cypress.config.js b/npm/react/examples/visual-testing-with-happo/cypress.config.js new file mode 100644 index 0000000000..550d6c4bdd --- /dev/null +++ b/npm/react/examples/visual-testing-with-happo/cypress.config.js @@ -0,0 +1,20 @@ +module.exports = { + 'video': false, + 'viewportWidth': 400, + 'viewportHeight': 700, + 'component': { + setupNodeEvents (on, config) { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/cypress-react-unit-test#install + const devServer = require('@cypress/react/plugins/react-scripts') + const happoTask = require('happo-cypress/task') + + on('task', happoTask) + devServer(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} diff --git a/npm/react/examples/visual-testing-with-happo/cypress.json b/npm/react/examples/visual-testing-with-happo/cypress.json deleted file mode 100644 index 18d423f08d..0000000000 --- a/npm/react/examples/visual-testing-with-happo/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 400, - "viewportHeight": 700, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/visual-sudoku/cypress/integration/cy-spec.js b/npm/react/examples/visual-testing-with-happo/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/visual-sudoku/cypress/integration/cy-spec.js rename to npm/react/examples/visual-testing-with-happo/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/visual-testing-with-happo/cypress/plugins/index.js b/npm/react/examples/visual-testing-with-happo/cypress/plugins/index.js deleted file mode 100644 index 904fb66314..0000000000 --- a/npm/react/examples/visual-testing-with-happo/cypress/plugins/index.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/cypress-react-unit-test#install -const devServer = require('@cypress/react/plugins/react-scripts') -// @ts-ignore -const happoTask = require('happo-cypress/task') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - on('task', happoTask) - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/visual-testing-with-happo/cypress/support/component-index.html b/npm/react/examples/visual-testing-with-happo/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/visual-testing-with-happo/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-happo/cypress/support/index.js b/npm/react/examples/visual-testing-with-happo/cypress/support/component.js similarity index 100% rename from npm/react/examples/visual-testing-with-happo/cypress/support/index.js rename to npm/react/examples/visual-testing-with-happo/cypress/support/component.js diff --git a/npm/react/examples/visual-testing-with-happo/package.json b/npm/react/examples/visual-testing-with-happo/package.json index de43ef28b6..4ee061df6b 100644 --- a/npm/react/examples/visual-testing-with-happo/package.json +++ b/npm/react/examples/visual-testing-with-happo/package.json @@ -3,8 +3,8 @@ "description": "Visual component testing using Happo.io", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct", + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component", "test:happo": "../../node_modules/.bin/happo-cypress -- npm test" }, "devDependencies": { diff --git a/npm/react/examples/visual-testing-with-happo/src/Calendar.cy-spec.js b/npm/react/examples/visual-testing-with-happo/src/Calendar.cy.js similarity index 100% rename from npm/react/examples/visual-testing-with-happo/src/Calendar.cy-spec.js rename to npm/react/examples/visual-testing-with-happo/src/Calendar.cy.js diff --git a/npm/react/examples/visual-testing-with-percy/cypress.config.js b/npm/react/examples/visual-testing-with-percy/cypress.config.js new file mode 100644 index 0000000000..4ee9e9cb19 --- /dev/null +++ b/npm/react/examples/visual-testing-with-percy/cypress.config.js @@ -0,0 +1,19 @@ +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'component': { + setupNodeEvents (on, config) { + // load file devServer that comes with this plugin + // https://github.com/bahmutov/@cypress/react#install + const devServer = require('@cypress/react/plugins/react-scripts') + + devServer(on, config) + + // IMPORTANT to return the config object + // with the any changed environment variables + return config + }, + }, +} diff --git a/npm/react/examples/visual-testing-with-percy/cypress.json b/npm/react/examples/visual-testing-with-percy/cypress.json deleted file mode 100644 index b268172ca3..0000000000 --- a/npm/react/examples/visual-testing-with-percy/cypress.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500, - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-applitools/cypress/integration/cy-spec.js b/npm/react/examples/visual-testing-with-percy/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/visual-testing-with-applitools/cypress/integration/cy-spec.js rename to npm/react/examples/visual-testing-with-percy/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/visual-testing-with-percy/cypress/plugins/index.js b/npm/react/examples/visual-testing-with-percy/cypress/plugins/index.js deleted file mode 100644 index f1c3bae07a..0000000000 --- a/npm/react/examples/visual-testing-with-percy/cypress/plugins/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @ts-check - -// load file devServer that comes with this plugin -// https://github.com/bahmutov/@cypress/react#install -const devServer = require('@cypress/react/plugins/react-scripts') - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - devServer(on, config) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/visual-testing-with-percy/cypress/support/component-index.html b/npm/react/examples/visual-testing-with-percy/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/visual-testing-with-percy/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-percy/cypress/support/index.js b/npm/react/examples/visual-testing-with-percy/cypress/support/component.js similarity index 100% rename from npm/react/examples/visual-testing-with-percy/cypress/support/index.js rename to npm/react/examples/visual-testing-with-percy/cypress/support/component.js diff --git a/npm/react/examples/visual-testing-with-percy/package.json b/npm/react/examples/visual-testing-with-percy/package.json index f97b40e5a7..c7f289bfff 100644 --- a/npm/react/examples/visual-testing-with-percy/package.json +++ b/npm/react/examples/visual-testing-with-percy/package.json @@ -3,8 +3,8 @@ "description": "Visual diffing for component testing", "private": true, "scripts": { - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct" + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/visual-testing-with-percy/src/DatePicker.cy-spec.js b/npm/react/examples/visual-testing-with-percy/src/DatePicker.cy.js similarity index 100% rename from npm/react/examples/visual-testing-with-percy/src/DatePicker.cy-spec.js rename to npm/react/examples/visual-testing-with-percy/src/DatePicker.cy.js diff --git a/npm/react/examples/webpack-file/cypress.config.js b/npm/react/examples/webpack-file/cypress.config.js new file mode 100644 index 0000000000..e045b5f053 --- /dev/null +++ b/npm/react/examples/webpack-file/cypress.config.js @@ -0,0 +1,16 @@ +const { defineConfig } = require('cypress') +const { devServer } = require('@cypress/react/plugins/load-webpack') + +module.exports = defineConfig({ + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'component': { + devServer, + devServerConfig: { + // from the root of the project (folder with cypress.config.{ts|js} file) + webpackFilename: 'webpack.config.js', + }, + }, +}) diff --git a/npm/react/examples/webpack-file/cypress.json b/npm/react/examples/webpack-file/cypress.json deleted file mode 100644 index 707979192c..0000000000 --- a/npm/react/examples/webpack-file/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/examples/visual-testing-with-happo/cypress/integration/cy-spec.js b/npm/react/examples/webpack-file/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/visual-testing-with-happo/cypress/integration/cy-spec.js rename to npm/react/examples/webpack-file/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/webpack-file/cypress/integration/cy-spec.js b/npm/react/examples/webpack-file/cypress/integration/cy-spec.js deleted file mode 100644 index d815fd540b..0000000000 --- a/npm/react/examples/webpack-file/cypress/integration/cy-spec.js +++ /dev/null @@ -1,6 +0,0 @@ -/// -describe('integration spec', () => { - it('works', () => { - expect(1).to.equal(1) - }) -}) diff --git a/npm/react/examples/webpack-file/cypress/plugins/index.js b/npm/react/examples/webpack-file/cypress/plugins/index.js deleted file mode 100644 index 84c951a310..0000000000 --- a/npm/react/examples/webpack-file/cypress/plugins/index.js +++ /dev/null @@ -1,15 +0,0 @@ -// @ts-check - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - require('@cypress/react/plugins/load-webpack')(on, config, { - // from the root of the project (folder with cypress.json file) - webpackFilename: 'webpack.config.js', - }) - - // IMPORTANT to return the config object - // with the any changed environment variables - return config -} diff --git a/npm/react/examples/webpack-file/cypress/support/component-index.html b/npm/react/examples/webpack-file/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/webpack-file/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/webpack-file/cypress/support/index.js b/npm/react/examples/webpack-file/cypress/support/component.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/support/index.js rename to npm/react/examples/webpack-file/cypress/support/component.js diff --git a/npm/react/examples/webpack-file/package.json b/npm/react/examples/webpack-file/package.json index cb87bb7c68..55a86da943 100644 --- a/npm/react/examples/webpack-file/package.json +++ b/npm/react/examples/webpack-file/package.json @@ -4,9 +4,9 @@ "private": true, "scripts": { "check-coverage": "check-coverage Test.js calc.js ParentComponent.js ChildComponent.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered Test.js calc.js ParentComponent.js ChildComponent.js", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@cypress/react": "file:../../dist", diff --git a/npm/react/examples/webpack-file/cypress/component/ChildComponent.js b/npm/react/examples/webpack-file/src/ChildComponent.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/ChildComponent.js rename to npm/react/examples/webpack-file/src/ChildComponent.js diff --git a/npm/react/examples/webpack-file/cypress/component/Mock.cy-spec.js b/npm/react/examples/webpack-file/src/Mock.cy.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/Mock.cy-spec.js rename to npm/react/examples/webpack-file/src/Mock.cy.js diff --git a/npm/react/examples/webpack-file/cypress/component/ParentComponent.js b/npm/react/examples/webpack-file/src/ParentComponent.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/ParentComponent.js rename to npm/react/examples/webpack-file/src/ParentComponent.js diff --git a/npm/react/examples/webpack-file/cypress/component/Test.cy-spec.js b/npm/react/examples/webpack-file/src/Test.cy.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/Test.cy-spec.js rename to npm/react/examples/webpack-file/src/Test.cy.js diff --git a/npm/react/examples/webpack-file/cypress/component/Test.js b/npm/react/examples/webpack-file/src/Test.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/Test.js rename to npm/react/examples/webpack-file/src/Test.js diff --git a/npm/react/examples/webpack-file/cypress/component/calc.js b/npm/react/examples/webpack-file/src/calc.js similarity index 100% rename from npm/react/examples/webpack-file/cypress/component/calc.js rename to npm/react/examples/webpack-file/src/calc.js diff --git a/npm/react/examples/webpack-options/cypress.config.js b/npm/react/examples/webpack-options/cypress.config.js new file mode 100644 index 0000000000..5fdd1589d4 --- /dev/null +++ b/npm/react/examples/webpack-options/cypress.config.js @@ -0,0 +1,41 @@ +const { devServer } = require('@cypress/webpack-dev-server') + +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'viewportWidth': 500, + 'viewportHeight': 500, + 'component': { + devServer (cypressDevServerConfig) { + const path = require('path') + const babelConfig = require('./babel.config') + + /** @type import("webpack").Configuration */ + const webpackConfig = { + resolve: { + extensions: ['.js', '.ts', '.jsx', '.tsx'], + }, + mode: 'development', + devtool: false, + output: { + publicPath: '/', + chunkFilename: '[name].bundle.js', + }, + // TODO: update with valid configuration for your components + module: { + rules: [ + { + test: /\.(js|jsx|mjs|ts|tsx)$/, + loader: 'babel-loader', + options: { ...babelConfig, cacheDirectory: path.resolve(__dirname, '.babel-cache') }, + }, + ], + }, + } + + process.env.BABEL_ENV = 'test' // this is required to load commonjs babel plugin + + return devServer(cypressDevServerConfig, { webpackConfig }) + }, + }, +} diff --git a/npm/react/examples/webpack-options/cypress.json b/npm/react/examples/webpack-options/cypress.json deleted file mode 100644 index 707979192c..0000000000 --- a/npm/react/examples/webpack-options/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*cy-spec.js", - "viewportWidth": 500, - "viewportHeight": 500 -} \ No newline at end of file diff --git a/npm/react/examples/webpack-options/cypress/component/Mock.cy-spec.js b/npm/react/examples/webpack-options/cypress/component/Mock.cy.js similarity index 100% rename from npm/react/examples/webpack-options/cypress/component/Mock.cy-spec.js rename to npm/react/examples/webpack-options/cypress/component/Mock.cy.js diff --git a/npm/react/examples/webpack-options/cypress/component/Test.cy-spec.js b/npm/react/examples/webpack-options/cypress/component/Test.cy.js similarity index 100% rename from npm/react/examples/webpack-options/cypress/component/Test.cy-spec.js rename to npm/react/examples/webpack-options/cypress/component/Test.cy.js diff --git a/npm/react/examples/visual-testing-with-percy/cypress/integration/cy-spec.js b/npm/react/examples/webpack-options/cypress/e2e/spec.cy.js similarity index 100% rename from npm/react/examples/visual-testing-with-percy/cypress/integration/cy-spec.js rename to npm/react/examples/webpack-options/cypress/e2e/spec.cy.js diff --git a/npm/react/examples/webpack-options/cypress/integration/cy-spec.js b/npm/react/examples/webpack-options/cypress/integration/cy-spec.js deleted file mode 100644 index d815fd540b..0000000000 --- a/npm/react/examples/webpack-options/cypress/integration/cy-spec.js +++ /dev/null @@ -1,6 +0,0 @@ -/// -describe('integration spec', () => { - it('works', () => { - expect(1).to.equal(1) - }) -}) diff --git a/npm/react/examples/webpack-options/cypress/plugins/index.js b/npm/react/examples/webpack-options/cypress/plugins/index.js deleted file mode 100644 index 4895d52da3..0000000000 --- a/npm/react/examples/webpack-options/cypress/plugins/index.js +++ /dev/null @@ -1,40 +0,0 @@ -// @ts-check -const path = require('path') -const { startDevServer } = require('@cypress/webpack-dev-server') -const babelConfig = require('../../babel.config') - -/** - * Cypress Webpack devServer includes Babel env preset, - * but to transpile JSX code we need to add Babel React preset - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - /** @type import("webpack").Configuration */ - const webpackConfig = { - resolve: { - extensions: ['.js', '.ts', '.jsx', '.tsx'], - }, - mode: 'development', - devtool: false, - output: { - publicPath: '/', - chunkFilename: '[name].bundle.js', - }, - // TODO: update with valid configuration for your components - module: { - rules: [ - { - test: /\.(js|jsx|mjs|ts|tsx)$/, - loader: 'babel-loader', - options: { ...babelConfig, cacheDirectory: path.resolve(__dirname, '.babel-cache') }, - }, - ], - }, - } - - process.env.BABEL_ENV = 'test' // this is required to load commonjs babel plugin - on('dev-server:start', (options) => startDevServer({ options, webpackConfig })) - - // if adding code coverage, important to return updated config - return config -} diff --git a/npm/react/examples/webpack-options/cypress/support/component-index.html b/npm/react/examples/webpack-options/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/react/examples/webpack-options/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/react/examples/webpack-options/cypress/support/index.js b/npm/react/examples/webpack-options/cypress/support/component.js similarity index 100% rename from npm/react/examples/webpack-options/cypress/support/index.js rename to npm/react/examples/webpack-options/cypress/support/component.js diff --git a/npm/react/examples/webpack-options/package.json b/npm/react/examples/webpack-options/package.json index 27d4eb4aea..96c8bb4bad 100644 --- a/npm/react/examples/webpack-options/package.json +++ b/npm/react/examples/webpack-options/package.json @@ -4,9 +4,9 @@ "private": true, "scripts": { "check-coverage": "check-coverage Test.js calc.js ParentComponent.js ChildComponent.js", - "cy:open": "node ../../../../scripts/cypress open-ct", + "cy:open": "node ../../../../scripts/cypress open --component", "only-covered": "only-covered Test.js calc.js ParentComponent.js ChildComponent.js", - "test": "node ../../../../scripts/cypress run-ct" + "test": "node ../../../../scripts/cypress run --component" }, "devDependencies": { "@babel/core": "7.4.5", diff --git a/npm/react/package.json b/npm/react/package.json index fc358607b0..4117d24c74 100644 --- a/npm/react/package.json +++ b/npm/react/package.json @@ -5,10 +5,11 @@ "main": "dist/cypress-react.cjs.js", "scripts": { "build": "rimraf dist && yarn transpile-plugins && rollup -c rollup.config.js", + "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", "build-prod": "yarn build", - "cy:open": "node ../../scripts/cypress.js open-ct", + "cy:open": "node ../../scripts/cypress.js open --component", "cy:open:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}", - "cy:run": "node ../../scripts/cypress.js run-ct", + "cy:run": "node ../../scripts/cypress.js run --component", "cy:run:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}", "pretest": "yarn transpile", "test": "yarn test-unit && yarn test-component", @@ -20,7 +21,6 @@ "watch": "yarn build --watch --watch.exclude ./dist/**/*" }, "dependencies": { - "@cypress/mount-utils": "0.0.0-development", "debug": "^4.3.2", "find-webpack": "2.2.1", "find-yarn-workspace-root": "2.0.0" @@ -36,6 +36,7 @@ "@bahmutov/cy-api": "1.4.2", "@bahmutov/cy-rollup": "2.0.0", "@cypress/code-coverage": "3.9.4", + "@cypress/mount-utils": "0.0.0-development", "@cypress/webpack-dev-server": "0.0.0-development", "@date-io/date-fns": "1", "@emotion/babel-preset-css-prop": "10.0.27", @@ -94,7 +95,7 @@ "svg-url-loader": "3.0.3", "typescript": "^4.2.3", "victory": "34.3.6", - "webpack": "4.44.1", + "webpack": "^4.44.2", "webpack-cli": "3.3.9" }, "peerDependencies": { diff --git a/npm/react/plugins/babel/index.d.ts b/npm/react/plugins/babel/index.d.ts index 18cd58a5af..8b7136c913 100644 --- a/npm/react/plugins/babel/index.d.ts +++ b/npm/react/plugins/babel/index.d.ts @@ -1,6 +1,6 @@ import { Configuration } from "webpack"; -declare namespace legacyDevServer { +declare namespace CypressBabelDevServer { interface CypressBabelDevServerConfig { /** * Allows to adjust the webpackConfig that our dev-server will use @@ -10,11 +10,6 @@ declare namespace legacyDevServer { setWebpackConfig?(config:Configuration): Configuration } - /** - * Type helper to make writing `CypressBabelDevServerConfig` easier - */ - function defineDevServerConfig(devServerConfig: CypressBabelDevServerConfig): CypressBabelDevServerConfig - /** * Sets up a webpack dev server with the proper configuration for babel transpilation * @param cypressDevServerConfig comes from the `devServer()` function first argument @@ -30,6 +25,6 @@ declare namespace legacyDevServer { * @param config comes from the argument of the `pluginsFile` function * @param devServerConfig additional config object (create an empty object it to see how to use it) */ -declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressBabelDevServerConfig): void +declare function CypressBabelDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: CypressBabelDevServer.CypressBabelDevServerConfig): void -export = legacyDevServer; \ No newline at end of file +export = CypressBabelDevServer; \ No newline at end of file diff --git a/npm/react/plugins/babel/index.js b/npm/react/plugins/babel/index.js index 1b0370ff0a..c966a3ce44 100644 --- a/npm/react/plugins/babel/index.js +++ b/npm/react/plugins/babel/index.js @@ -2,7 +2,7 @@ const { startDevServer } = require('@cypress/webpack-dev-server') const getBabelWebpackConfig = require('./getBabelWebpackConfig') const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server') -function devServer (cypressDevServerConfig, devServerConfig) { +function devServer (cypressDevServerConfig, devServerConfig = {}) { return startDevServer({ options: cypressDevServerConfig, webpackConfig: getBabelWebpackConfig(cypressDevServerConfig.config, devServerConfig), @@ -18,7 +18,3 @@ module.exports = getLegacyDevServer(devServer, (config) => { // New signature module.exports.devServer = devServer - -module.exports.defineDevServerConfig = function (devServerConfig) { - return devServerConfig -} diff --git a/npm/react/plugins/craco/index.d.ts b/npm/react/plugins/craco/index.d.ts index b4149904d6..d3b6f1b735 100644 --- a/npm/react/plugins/craco/index.d.ts +++ b/npm/react/plugins/craco/index.d.ts @@ -1,4 +1,4 @@ -declare namespace legacyDevServer { +declare namespace CypressCracoDevServer { interface CypressCracoDevServerConfig { /** * The object exported of your craco.config.js file @@ -6,11 +6,6 @@ declare namespace legacyDevServer { cracoConfig: any } - /** - * Type helper to make writing `CypressCracoDevServerConfig` easier - */ - function defineDevServerConfig(devServerConfig: CypressCracoDevServerConfig): CypressCracoDevServerConfig - /** * Sets up a dev server for using Cypress compoennt testing with CRACO (https://github.com/gsoft-inc/craco) * @param cypressDevServerConfig comes from the `devServer()` function first argument @@ -26,6 +21,6 @@ declare namespace legacyDevServer { * @param config comes from the argument of the `pluginsFile` function * @param cracoConfig the object exported of your craco.config.js file */ -declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, cracoConfig: any): void +declare function CypressCracoDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, cracoConfig: any): void -export = legacyDevServer; \ No newline at end of file +export = CypressCracoDevServer; \ No newline at end of file diff --git a/npm/react/plugins/craco/index.js b/npm/react/plugins/craco/index.js index d1a90301d3..1cdff6b6a7 100644 --- a/npm/react/plugins/craco/index.js +++ b/npm/react/plugins/craco/index.js @@ -23,7 +23,3 @@ module.exports = getLegacyDevServer(devServer, (config) => { module.exports.devServer = (cypressDevServerConfig, { cracoConfig }) => { return devServer(cypressDevServerConfig, cracoConfig) } - -module.exports.defineDevServerConfig = function (devServerConfig) { - return devServerConfig -} diff --git a/npm/react/plugins/load-webpack/index.d.ts b/npm/react/plugins/load-webpack/index.d.ts index 93d64dfc2e..54bf097613 100644 --- a/npm/react/plugins/load-webpack/index.d.ts +++ b/npm/react/plugins/load-webpack/index.d.ts @@ -1,4 +1,4 @@ -declare namespace legacyDevServer { +declare namespace CypressWebpackDevServer { interface CypressWebpackDevServerConfig { /** * Location of the weppack.config Cypress should use @@ -6,11 +6,6 @@ declare namespace legacyDevServer { webpackFilename?: string } - /** - * Type helper to make writing `CypressWebpackDevServerConfig` easier - */ - function defineDevServerConfig(devServerConfig: CypressWebpackDevServerConfig): CypressWebpackDevServerConfig - /** * Sets up a webpack dev server with the proper configuration for babel transpilation * @param cypressDevServerConfig comes from the `devServer()` function first argument @@ -26,6 +21,6 @@ declare namespace legacyDevServer { * @param config comes from the argument of the `pluginsFile` function * @param devServerConfig additional config object (create an empty object to see how to use it) */ -declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressWebpackDevServerConfig): void +declare function CypressWebpackDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: CypressWebpackDevServer.CypressWebpackDevServerConfig): void -export = legacyDevServer; \ No newline at end of file +export = CypressWebpackDevServer; \ No newline at end of file diff --git a/npm/react/plugins/load-webpack/index.js b/npm/react/plugins/load-webpack/index.js index a995e2a46e..3c135132ce 100644 --- a/npm/react/plugins/load-webpack/index.js +++ b/npm/react/plugins/load-webpack/index.js @@ -12,7 +12,7 @@ function normalizeWebpackPath (config, webpackConfigPath) { /** * Injects dev-server based on the webpack config file. * - * **Important:** `webpackFilename` path is relative to the project root (cypress.json location) + * **Important:** `webpackFilename` path is relative to the project root (cypress.config.{ts|js} location) * @type {(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options: { webpackFilename: string }) => Cypress.PluginConfigOptions} */ function devServer (cypressDevServerConfig, { webpackFilename }) { @@ -37,7 +37,3 @@ module.exports = getLegacyDevServer(devServer, (config) => { // New signature module.exports.devServer = devServer - -module.exports.defineDevServerConfig = function (devServerConfig) { - return devServerConfig -} diff --git a/npm/react/plugins/next/index-template.html b/npm/react/plugins/next/index-template.html deleted file mode 100644 index ec059c3d78..0000000000 --- a/npm/react/plugins/next/index-template.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Components App -
- - -
- - diff --git a/npm/react/plugins/next/index.d.ts b/npm/react/plugins/next/index.d.ts index 00d2d4f6a9..9c720e1b29 100644 --- a/npm/react/plugins/next/index.d.ts +++ b/npm/react/plugins/next/index.d.ts @@ -1,17 +1,20 @@ -/** - * Sets up a Cypress component testing environment for your NextJs application - * @param on comes from the argument of the `pluginsFile` function - * @param config comes from the argument of the `pluginsFile` function - */ -declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions): void +declare namespace CypressNextDevServer { + interface CypressNextDevServerConfig {} -declare namespace legacyDevServer { /** * Sets up a Cypress component testing environment for your NextJs application * @param cypressDevServerConfig comes from the `devServer()` function first argument * @returns the resolved dev server object that cypress can use to start testing */ - function devServer(cypressDevServerConfig: Cypress.DevServerConfig): Cypress.ResolvedDevServerConfig + function devServer(cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressNextDevServerConfig): Cypress.ResolvedDevServerConfig } -export = legacyDevServer; \ No newline at end of file +/** + * Sets up a Cypress component testing environment for your NextJs application + * @param on comes from the argument of the `pluginsFile` function + * @param config comes from the argument of the `pluginsFile` function + * @param devServerConfig additional config object (create an empty object to see how to use it) + */ +declare function CypressNextDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: CypressNextDevServer.CypressNextDevServerConfig): void + +export = CypressNextDevServer; \ No newline at end of file diff --git a/npm/react/plugins/next/index.js b/npm/react/plugins/next/index.js index 645527669a..03e0628d15 100644 --- a/npm/react/plugins/next/index.js +++ b/npm/react/plugins/next/index.js @@ -1,4 +1,3 @@ -const path = require('path') const findNextWebpackConfig = require('./findNextWebpackConfig') const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server') @@ -11,7 +10,6 @@ async function devServer (cypressDevServerConfig) { return startDevServer({ options: cypressDevServerConfig, webpackConfig, - template: path.resolve(__dirname, 'index-template.html'), }) } diff --git a/npm/react/plugins/react-scripts/index.d.ts b/npm/react/plugins/react-scripts/index.d.ts index 46c4ad8ad6..cbaeaba7e9 100644 --- a/npm/react/plugins/react-scripts/index.d.ts +++ b/npm/react/plugins/react-scripts/index.d.ts @@ -1,4 +1,4 @@ -declare namespace legacyDevServer { +declare namespace CypressCRADevServer { interface CypressCRADevServerConfig { /** * Location of the weppack.config Cypress should use @@ -6,11 +6,6 @@ declare namespace legacyDevServer { webpackConfigPath?: string } - /** - * Type helper to make writing `CypressCRADevServerConfig` easier - */ - function defineDevServerConfig(devServerConfig: CypressCRADevServerConfig): CypressCRADevServerConfig - /** * Sets up a Cypress component testing environment for your Create React App environment * @param cypressDevServerConfig comes from the `devServer()` function first argument @@ -26,6 +21,6 @@ declare namespace legacyDevServer { * @param config comes from the argument of the `pluginsFile` function * @param devServerConfig additional config object (create an empty object to see how to use it) */ -declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressCRADevServerConfig): void +declare function CypressCRADevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: CypressCRADevServer.CypressCRADevServerConfig): void -export = legacyDevServer; \ No newline at end of file +export = CypressCRADevServer; \ No newline at end of file diff --git a/npm/react/plugins/react-scripts/index.js b/npm/react/plugins/react-scripts/index.js index e8502d9409..45a23de6fd 100644 --- a/npm/react/plugins/react-scripts/index.js +++ b/npm/react/plugins/react-scripts/index.js @@ -4,13 +4,11 @@ const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server') function devServer (cypressDevServerConfig, { webpackConfigPath, -} = { - webpackConfigPath: 'react-scripts/config/webpack.config', -}) { +} = {}) { return startDevServer({ options: cypressDevServerConfig, webpackConfig: findReactScriptsWebpackConfig(cypressDevServerConfig.config, { - webpackConfigPath, + webpackConfigPath: webpackConfigPath || 'react-scripts/config/webpack.config', }), }) } @@ -24,7 +22,3 @@ module.exports = getLegacyDevServer(devServer, (config) => { // New signature module.exports.devServer = devServer - -module.exports.defineDevServerConfig = function (devServerConfig) { - return devServerConfig -} diff --git a/npm/react/plugins/utils/get-transpile-folders.js b/npm/react/plugins/utils/get-transpile-folders.js index 1c8feeaf85..89de6e79c4 100644 --- a/npm/react/plugins/utils/get-transpile-folders.js +++ b/npm/react/plugins/utils/get-transpile-folders.js @@ -5,20 +5,45 @@ function getTranspileFolders (config) { const rawFolders = config.addTranspiledFolders || [] const folders = rawFolders.map((folder) => path.resolve(config.projectRoot, folder)) - // user can disable folders, so check first - if (config.componentFolder) { - folders.push(config.componentFolder) + // ensure path is absolute + const ensureAbs = (folder) => { + if (!path.isAbsolute(folder)) { + return path.resolve(folder) + } + + return folder } if (config.fixturesFolder) { - folders.push(config.fixturesFolder) + folders.push(ensureAbs(config.fixturesFolder)) } if (config.supportFolder) { - folders.push(config.supportFolder) + folders.push(ensureAbs(config.supportFolder)) } - return folders + // attempt to add directories based on spec pattern + let componentDirs = config.specPattern || '' + + // can be string or array + if (typeof componentDirs === 'string') { + componentDirs = [componentDirs] + } + + const dirsFromSpecPattern = componentDirs.reduce((acc, curr) => { + // glob + if (curr.includes('*')) { + const parts = curr.slice(0, curr.indexOf('*') - 1) + const joined = parts.split(path.sep) + const dir = path.join(...joined) + + return acc.concat(path.resolve(config.projectRoot, dir)) + } + + return acc + }, []) + + return folders.concat(...dirsFromSpecPattern, path.resolve('cypress')) } module.exports = { getTranspileFolders } diff --git a/npm/react/rollup.config.js b/npm/react/rollup.config.js index 1ece28e9a8..e582516a80 100644 --- a/npm/react/rollup.config.js +++ b/npm/react/rollup.config.js @@ -24,7 +24,6 @@ function createEntry (options) { external: [ 'react', 'react-dom', - '@cypress/mount-utils', ], plugins: [ resolve(), commonjs(), diff --git a/npm/react/src/mount.ts b/npm/react/src/mount.ts index d6e2b5f7f4..da17a97b85 100644 --- a/npm/react/src/mount.ts +++ b/npm/react/src/mount.ts @@ -4,7 +4,8 @@ import getDisplayName from './getDisplayName' import { injectStylesBeforeElement, StyleOptions, - ROOT_ID, + getContainerEl, + ROOT_SELECTOR, setupHooks, } from '@cypress/mount-utils' @@ -12,8 +13,8 @@ import { * Inject custom style text or CSS file or 3rd party style resources */ const injectStyles = (options: MountOptions) => { - return () => { - const el = document.getElementById(ROOT_ID) + return (): HTMLElement => { + const el = getContainerEl() return injectStylesBeforeElement(options, document, el) } @@ -66,12 +67,12 @@ const _mount = (type: 'mount' | 'rerender', jsx: React.ReactNode, options: Mount lastMountedReactDom = reactDomToUse - const el = document.getElementById(ROOT_ID) + const el = getContainerEl() if (!el) { throw new Error( [ - '[@cypress/react] ๐Ÿ”ฅ Hmm, cannot find root element to mount the component.', + `[@cypress/react] ๐Ÿ”ฅ Hmm, cannot find root element to mount the component. Searched for ${ROOT_SELECTOR}`, ].join(' '), ) } @@ -102,6 +103,7 @@ const _mount = (type: 'mount' | 'rerender', jsx: React.ReactNode, options: Mount name: type, type: 'parent', message: [message], + // @ts-ignore $el: (el.children.item(0) as unknown) as JQuery, consoleProps: () => { return { @@ -150,13 +152,12 @@ const _mount = (type: 'mount' | 'rerender', jsx: React.ReactNode, options: Mount }) ``` */ +// @ts-ignore export const unmount = (options = { log: true }): globalThis.Cypress.Chainable> => _unmount(options) const _unmount = (options: { boundComponentMessage?: string, log: boolean }) => { return cy.then(() => { - const selector = `#${ROOT_ID}` - - return cy.get(selector, { log: false }).then(($el) => { + return cy.get(ROOT_SELECTOR, { log: false }).then(($el) => { if (lastMountedReactDom) { const wasUnmounted = lastMountedReactDom.unmountComponentAtNode($el[0]) @@ -183,7 +184,7 @@ const _unmount = (options: { boundComponentMessage?: string, log: boolean }) => // NOTE: we cannot use unmount here because // we are not in the context of a test const preMountCleanup = () => { - const el = document.getElementById(ROOT_ID) + const el = getContainerEl() if (el && lastMountedReactDom) { lastMountedReactDom.unmountComponentAtNode(el) @@ -264,6 +265,7 @@ export interface MountReturn { * Removes the mounted component. * @see `unmount` */ + // @ts-ignore unmount: () => globalThis.Cypress.Chainable> } diff --git a/npm/vite-dev-server-fresh/.eslintrc b/npm/vite-dev-server-fresh/.eslintrc new file mode 100644 index 0000000000..5dbf8f7f86 --- /dev/null +++ b/npm/vite-dev-server-fresh/.eslintrc @@ -0,0 +1,55 @@ +{ + "plugins": [ + "cypress", + "@cypress/dev" + ], + "extends": [ + "plugin:@cypress/dev/general", + "plugin:@cypress/dev/tests", + "plugin:@cypress/dev/react" + ], + "parser": "vue-eslint-parser", + "parserOptions": { + "parser": "@typescript-eslint/parser" + }, + "env": { + "cypress/globals": true + }, + "globals": { + "jest": "readonly" + }, + "rules": { + "no-console": "off", + "mocha/no-global-tests": "off", + "@typescript-eslint/no-unused-vars": "off", + "react/jsx-filename-extension": [ + "warn", + { + "extensions": [ + ".js", + ".jsx", + ".tsx" + ] + } + ] + }, + "overrides": [ + { + "files": [ + "lib/*" + ], + "rules": { + "no-console": 1 + } + }, + { + "files": [ + "**/*.json" + ], + "rules": { + "quotes": "off", + "comma-dangle": "off" + } + } + ] +} diff --git a/npm/vite-dev-server-fresh/.gitignore b/npm/vite-dev-server-fresh/.gitignore new file mode 100644 index 0000000000..4068db97ef --- /dev/null +++ b/npm/vite-dev-server-fresh/.gitignore @@ -0,0 +1 @@ +cypress/videos/* \ No newline at end of file diff --git a/npm/vite-dev-server-fresh/README.md b/npm/vite-dev-server-fresh/README.md new file mode 100644 index 0000000000..245a18945e --- /dev/null +++ b/npm/vite-dev-server-fresh/README.md @@ -0,0 +1,52 @@ +# @cypress/vite-dev-server-fresh + +Implements the APIs for the object-syntax of the Cypress Component-testing "vite dev server". + +Object syntax: + +```ts +import { defineConfig } from 'cypress' + +export default defineConfig({ + component: { + devServer: { + framework: 'create-react-app', + bundler: 'vite', + // viteConfig?: Will try to infer, if passed it will be used as is + } + } +}) +``` + +Function syntax: + +```ts +import { devServer } from '@cypress/vite-dev-server' +import { defineConfig } from 'cypress' + +export default defineConfig({ + component: { + devServer(cypressConfig) { + return devServer({ + cypressConfig, + framework: 'react', + viteConfig: require('./vite.config.js') + }) + } + } +}) +``` + +## Architecture + +There should be a single publicly-exported entrypoint for the module, `devServer`, all other types and functions should be considered internal/implementation details, and types stripped from the output. + +The `devServer` will first source the modules from the user's project, falling back to our own bundled versions of libraries. This ensures that the user has installed the current modules, and throws an error if the user does not have the library installed. + +From there, we check the "framework" field to source or define any known vite transforms to aid in the compilation. + +We then merge the sourced config with the user's vite config, and layer on our own transforms, and provide this to a vite instance. The vite instance used to create a vite-dev-server, which is returned. + +## Changelog + +[Changelog](./CHANGELOG.md) diff --git a/npm/vite-dev-server-fresh/client/initCypressTests.js b/npm/vite-dev-server-fresh/client/initCypressTests.js new file mode 100644 index 0000000000..3d38b93884 --- /dev/null +++ b/npm/vite-dev-server-fresh/client/initCypressTests.js @@ -0,0 +1,64 @@ +// This file is merged in a ${ + indexHtmlContent.substring(endOfBody) + }` + }, + configureServer: async (server: ViteDevServer) => { + server.middlewares.use(`${base}index.html`, async (req, res) => { + let transformedIndexHtml = await server.transformIndexHtml(base, '') + const viteImport = `` + + // If we're doing cy-in-cy, we need to be able to access the Cypress instance from the parent frame. + if (process.env.CYPRESS_INTERNAL_VITE_OPEN_MODE_TESTING) { + transformedIndexHtml = transformedIndexHtml.replace(viteImport, `${viteImport}`) + } + + return res.end(transformedIndexHtml) + }) + }, + handleHotUpdate: ({ server, file }) => { + debug('handleHotUpdate - file', file) + + // If the user provided IndexHtml is changed, do a full-reload + if (normalizePath(file) === resolve(projectRoot, indexHtmlFile)) { + server.ws.send({ + type: 'full-reload', + }) + + return + } + + // get the graph node for the file that just got updated + let moduleImporters = server.moduleGraph.fileToModulesMap.get(file) + let iterationNumber = 0 + + const exploredFiles = new Set() + + // until we reached a point where the current module is imported by no other + while (moduleImporters?.size) { + if (iterationNumber > HMR_DEPENDENCY_LOOKUP_MAX_ITERATION) { + debug(`max hmr iteration reached: ${HMR_DEPENDENCY_LOOKUP_MAX_ITERATION}; Rerun will not happen on this file change.`) + + return [] + } + + // as soon as we find one of the specs, we trigger the re-run of tests + for (const mod of moduleImporters.values()) { + debug('handleHotUpdate - mod.file', mod.file) + if (mod.file === supportFilePath) { + debug('handleHotUpdate - support compile success') + devServerEvents.emit('dev-server:compile:success') + + // if we update support we know we have to re-run it all + // no need to check further + return [] + } + + if (mod.file && specsPathsSet.has(mod.file)) { + debug('handleHotUpdate - spec compile success', mod.file) + devServerEvents.emit('dev-server:compile:success', { specFile: mod.file }) + // if we find one spec, does not mean we are done yet, + // there could be other spec files to re-run + // see https://github.com/cypress-io/cypress/issues/17691 + } + } + + // get all the modules that import the current one + moduleImporters = getImporters(moduleImporters, exploredFiles) + iterationNumber += 1 + } + + return [] + }, + } +} + +/** + * Gets all the modules that import the set of modules passed in parameters + * @param modules the set of module whose dependents to return + * @param alreadyExploredFiles set of files that have already been looked at and should be avoided in case of circular dependency + * @returns a set of ModuleMode that import directly the current modules + */ +function getImporters (modules: Set, alreadyExploredFiles: Set): Set { + const allImporters = new Set() + + modules.forEach((m) => { + if (m.file && !alreadyExploredFiles.has(m.file)) { + alreadyExploredFiles.add(m.file) + m.importers.forEach((imp) => { + allImporters.add(imp) + }) + } + }) + + return allImporters +} diff --git a/npm/vite-dev-server-fresh/src/plugins/index.ts b/npm/vite-dev-server-fresh/src/plugins/index.ts new file mode 100644 index 0000000000..f8eb18e0f5 --- /dev/null +++ b/npm/vite-dev-server-fresh/src/plugins/index.ts @@ -0,0 +1,3 @@ +export * from './inspect' + +export * from './cypress' diff --git a/npm/vite-dev-server-fresh/src/plugins/inspect.ts b/npm/vite-dev-server-fresh/src/plugins/inspect.ts new file mode 100644 index 0000000000..3f15524910 --- /dev/null +++ b/npm/vite-dev-server-fresh/src/plugins/inspect.ts @@ -0,0 +1,29 @@ +import debugFn from 'debug' +import type { PluginOption } from 'vite' + +const debug = debugFn('cypress:vite-dev-server:plugins:inspect') + +export const CypressInspect = async (): Promise => { + if (!process.env.CYPRESS_INTERNAL_VITE_INSPECT) { + debug('skipping vite inspect because CYPRESS_INTERNAL_VITE_INSPECT is not set') + + return null + } + + let Inspect + + try { + Inspect = (await import('vite-plugin-inspect')).default + debug('inspect was found', Inspect) + } catch (err) { + debug(`Tried to import the inspect plugin 'vite-plugin-inspect'. It's an optional peerDependency so install it if you'd like.`) + debug(err) + + return null + } + + return { + ...Inspect(), + name: 'cypress:inspect', + } +} diff --git a/npm/vite-dev-server-fresh/src/resolveConfig.ts b/npm/vite-dev-server-fresh/src/resolveConfig.ts new file mode 100644 index 0000000000..9af9423ab4 --- /dev/null +++ b/npm/vite-dev-server-fresh/src/resolveConfig.ts @@ -0,0 +1,73 @@ +/** + * The logic inside of this file is heavily reused from + * Vitest's own config resolution logic. + * You can find it here https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/create.ts + */ +import debugFn from 'debug' +import { importModule } from 'local-pkg' +import { relative, resolve } from 'pathe' +import { InlineConfig, mergeConfig } from 'vite' +import path from 'path' + +import { configFiles } from './constants' +import type { ViteDevServerConfig } from './devServer' +import { Cypress, CypressInspect } from './plugins/index' + +const debug = debugFn('cypress:vite-dev-server:resolve-config') + +export const createViteDevServerConfig = async (config: ViteDevServerConfig) => { + const { specs, cypressConfig, viteConfig: viteOverrides = {} } = config + const root = cypressConfig.projectRoot + const { default: findUp } = await importModule('find-up') + const configFile = await findUp(configFiles, { cwd: root } as { cwd: string }) + + // INFO logging, a lot is logged here. + // debug('all dev-server options are', options) + + if (configFile) { + debug('resolved config file at', configFile, 'using root', root) + } else if (viteOverrides) { + debug('Couldn\'t find a Vite config file, however we received a custom viteConfig', viteOverrides) + } else { + debug(` + Didn\'t resolve a Vite config AND the user didn\'t pass in a custom viteConfig. + Falling back to Vite\'s defaults.`) + } + + // Vite caches its output in the .vite directory in the node_modules where vite lives. + // So we want to find that node_modules path and ensure it's added to the "allow" list + const vitePathNodeModules = path.dirname(path.dirname(require.resolve(`vite/package.json`, { + paths: [root], + }))) + + const viteBaseConfig: InlineConfig = { + root, + base: `${cypressConfig.devServerPublicPathRoute}/`, + configFile, + optimizeDeps: { + entries: [ + ...specs.map((s) => relative(root, s.relative)), + ...(cypressConfig.supportFile ? [resolve(root, cypressConfig.supportFile)] : []), + ].filter((v) => v != null), + }, + server: { + fs: { + allow: [ + root, + vitePathNodeModules, + cypressConfig.cypressBinaryRoot, + ], + }, + }, + plugins: [ + Cypress(config), + await CypressInspect(), + ], + } + + const finalConfig = mergeConfig(viteBaseConfig, viteOverrides as Record) + + debug('The resolved server config is', JSON.stringify(finalConfig, null, 2)) + + return finalConfig +} diff --git a/npm/vite-dev-server-fresh/tsconfig.json b/npm/vite-dev-server-fresh/tsconfig.json new file mode 100644 index 0000000000..2fc619ba0d --- /dev/null +++ b/npm/vite-dev-server-fresh/tsconfig.json @@ -0,0 +1,54 @@ +{ + "compilerOptions": { + /* Basic Options */ + "resolveJsonModule": true, + "target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, + "lib": [ + "es2015", + "dom" + ] /* Specify library files to be included in the compilation: */, + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "dist" /* Redirect output structure to the directory. */, + // "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + "types": ["cypress"] /* Type declaration files to be included in compilation. */, + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "esModuleInterop": true, + /** Allows us to strip internal types sourced from webpack */ + "stripInternal": true, + "importsNotUsedAsValues": "error" + }, + "include": ["src"], + "exclude": ["node_modules", "*.js"] +} diff --git a/npm/vite-dev-server/.eslintrc b/npm/vite-dev-server/.eslintrc index fef43b39a0..5dbf8f7f86 100644 --- a/npm/vite-dev-server/.eslintrc +++ b/npm/vite-dev-server/.eslintrc @@ -8,7 +8,10 @@ "plugin:@cypress/dev/tests", "plugin:@cypress/dev/react" ], - "parser": "@typescript-eslint/parser", + "parser": "vue-eslint-parser", + "parserOptions": { + "parser": "@typescript-eslint/parser" + }, "env": { "cypress/globals": true }, diff --git a/npm/vite-dev-server/README.md b/npm/vite-dev-server/README.md index 19460ae263..df953e0bab 100644 --- a/npm/vite-dev-server/README.md +++ b/npm/vite-dev-server/README.md @@ -41,7 +41,7 @@ Install `@cypress/vue` or `@cypress/react` to get this package working properly - Responds to every query with the prefix `__cypress/src/` (base path should be this prefix). - Responds to `__cypress/src/index.html` with an html page. This page - - will contain an element `
`. Tis will be used by mount function to mount the app containing the components we want. + - will contain an element `
`. Tis will be used by mount function to mount the app containing the components we want. - will load support files - will load the current spec from the url - will start the test when both files are done loading diff --git a/npm/vite-dev-server/client/initCypressTests.js b/npm/vite-dev-server/client/initCypressTests.js index 4e34f06684..c418bbc685 100644 --- a/npm/vite-dev-server/client/initCypressTests.js +++ b/npm/vite-dev-server/client/initCypressTests.js @@ -1,19 +1,33 @@ // This file is merged in a diff --git a/npm/vite-dev-server/cypress/components/vue/Hello/Hello.spec.js b/npm/vite-dev-server/cypress/components/vue/Hello/Hello.cy.js similarity index 100% rename from npm/vite-dev-server/cypress/components/vue/Hello/Hello.spec.js rename to npm/vite-dev-server/cypress/components/vue/Hello/Hello.cy.js diff --git a/npm/vite-dev-server/cypress/components/vue/Hello/Hello.vue b/npm/vite-dev-server/cypress/components/vue/Hello/Hello.vue index 9aa1930da9..2ed430d78d 100644 --- a/npm/vite-dev-server/cypress/components/vue/Hello/Hello.vue +++ b/npm/vite-dev-server/cypress/components/vue/Hello/Hello.vue @@ -8,26 +8,27 @@ diff --git a/npm/vue/cypress/component/basic/small-examples/Repeater.spec.js b/npm/vue/cypress/component/basic/small-examples/Repeater.cy.js similarity index 100% rename from npm/vue/cypress/component/basic/small-examples/Repeater.spec.js rename to npm/vue/cypress/component/basic/small-examples/Repeater.cy.js diff --git a/npm/vue/cypress/component/basic/small-examples/Repeater.vue b/npm/vue/cypress/component/basic/small-examples/Repeater.vue index 05a1cdb661..c101d8e26d 100644 --- a/npm/vue/cypress/component/basic/small-examples/Repeater.vue +++ b/npm/vue/cypress/component/basic/small-examples/Repeater.vue @@ -1,17 +1,21 @@ diff --git a/npm/vue/cypress/component/basic/style-in-spec/Todo.vue b/npm/vue/cypress/component/basic/style-in-spec/Todo.vue index 183b565806..777025058c 100644 --- a/npm/vue/cypress/component/basic/style-in-spec/Todo.vue +++ b/npm/vue/cypress/component/basic/style-in-spec/Todo.vue @@ -1,29 +1,36 @@ diff --git a/npm/vue/cypress/component/basic/style-in-spec/todo-spec.js b/npm/vue/cypress/component/basic/style-in-spec/todo.cy.js similarity index 100% rename from npm/vue/cypress/component/basic/style-in-spec/todo-spec.js rename to npm/vue/cypress/component/basic/style-in-spec/todo.cy.js diff --git a/npm/vue/cypress/component/button/ButtonCounter.vue b/npm/vue/cypress/component/button/ButtonCounter.vue index 69ab00ef8c..35b6d5bfbd 100644 --- a/npm/vue/cypress/component/button/ButtonCounter.vue +++ b/npm/vue/cypress/component/button/ButtonCounter.vue @@ -1,22 +1,24 @@ - diff --git a/npm/vue/examples/code-coverage/src/components/TodoList.spec.js b/npm/vue/examples/code-coverage/src/components/TodoList.cy.js similarity index 100% rename from npm/vue/examples/code-coverage/src/components/TodoList.spec.js rename to npm/vue/examples/code-coverage/src/components/TodoList.cy.js diff --git a/npm/vue/examples/code-coverage/src/components/TodoList.vue b/npm/vue/examples/code-coverage/src/components/TodoList.vue index b3235f8a83..fc3ae269be 100644 --- a/npm/vue/examples/code-coverage/src/components/TodoList.vue +++ b/npm/vue/examples/code-coverage/src/components/TodoList.vue @@ -1,50 +1,60 @@ diff --git a/npm/vue/examples/code-coverage/src/components/TodoListItem.vue b/npm/vue/examples/code-coverage/src/components/TodoListItem.vue index e417329356..29bbdc82ef 100644 --- a/npm/vue/examples/code-coverage/src/components/TodoListItem.vue +++ b/npm/vue/examples/code-coverage/src/components/TodoListItem.vue @@ -1,7 +1,12 @@ @@ -10,8 +15,9 @@ export default { props: { todo: { type: Object, - required: true - } - } -}; + required: true, + }, + }, + emits: ['remove'], +} diff --git a/npm/vue/examples/code-coverage/src/index.js b/npm/vue/examples/code-coverage/src/index.js index 1eb120fc42..8c043dc51e 100644 --- a/npm/vue/examples/code-coverage/src/index.js +++ b/npm/vue/examples/code-coverage/src/index.js @@ -6,6 +6,6 @@ Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', - template: '', components: { App }, + template: '', }) diff --git a/npm/vue/examples/code-coverage/yarn.lock b/npm/vue/examples/code-coverage/yarn.lock index 4c62eca7f8..f39f28bbbb 100644 --- a/npm/vue/examples/code-coverage/yarn.lock +++ b/npm/vue/examples/code-coverage/yarn.lock @@ -224,10 +224,10 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@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.12.17": version "7.12.17" @@ -262,16 +262,16 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.0": - version "7.14.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.1.tgz#1bd644b5db3f5797c4479d89ec1817fe02b84c47" - integrity sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q== - "@babel/parser@^7.12.13", "@babel/parser@^7.13.16", "@babel/parser@^7.4.3", "@babel/parser@^7.4.5": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== +"@babel/parser@^7.15.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.13.15" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz#80e549df273a3b3050431b148c892491df1bcc5b" @@ -752,14 +752,6 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.0": - version "7.14.1" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.1.tgz#095bd12f1c08ab63eff6e8f7745fa7c9cc15a9db" - integrity sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - to-fast-properties "^2.0.0" - "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.13.17", "@babel/types@^7.4.0", "@babel/types@^7.4.4": version "7.13.17" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.17.tgz#48010a115c9fba7588b4437dd68c9469012b38b4" @@ -768,6 +760,14 @@ "@babel/helper-validator-identifier" "^7.12.11" to-fast-properties "^2.0.0" +"@babel/types@^7.15.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + "@cypress/browserify-preprocessor@3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz#ab86335b0c061d11f5ad7df03f06b1877b836f71" @@ -905,53 +905,53 @@ "@types/webpack-sources" "*" source-map "^0.6.0" -"@vue/compiler-core@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.11.tgz#5ef579e46d7b336b8735228758d1c2c505aae69a" - integrity sha512-6sFj6TBac1y2cWCvYCA8YzHJEbsVkX7zdRs/3yK/n1ilvRqcn983XvpBbnN3v4mZ1UiQycTvOiajJmOgN9EVgw== +"@vue/compiler-core@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.6.tgz#7162bb0670273f04566af0d353009187ab577915" + integrity sha512-vbwnz7+OhtLO5p5i630fTuQCL+MlUpEMTKHuX+RfetQ+3pFCkItt2JUH+9yMaBG2Hkz6av+T9mwN/acvtIwpbw== dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.0.11" - estree-walker "^2.0.1" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" + "@vue/shared" "3.2.6" + estree-walker "^2.0.2" source-map "^0.6.1" -"@vue/compiler-dom@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.11.tgz#b15fc1c909371fd671746020ba55b5dab4a730ee" - integrity sha512-+3xB50uGeY5Fv9eMKVJs2WSRULfgwaTJsy23OIltKgMrynnIj8hTYY2UL97HCoz78aDw1VDXdrBQ4qepWjnQcw== +"@vue/compiler-dom@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.6.tgz#3764d7fe1a696e39fb2a3c9d638da0749e369b2d" + integrity sha512-+a/3oBAzFIXhHt8L5IHJOTP4a5egzvpXYyi13jR7CUYOR1S+Zzv7vBWKYBnKyJLwnrxTZnTQVjeHCgJq743XKg== dependencies: - "@vue/compiler-core" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/compiler-core" "3.2.6" + "@vue/shared" "3.2.6" -"@vue/reactivity@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.11.tgz#07b588349fd05626b17f3500cbef7d4bdb4dbd0b" - integrity sha512-SKM3YKxtXHBPMf7yufXeBhCZ4XZDKP9/iXeQSC8bBO3ivBuzAi4aZi0bNoeE2IF2iGfP/AHEt1OU4ARj4ao/Xw== +"@vue/reactivity@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.6.tgz#b8993fa6f48545178e588e25a9c9431a1c1b7d50" + integrity sha512-8vIDD2wpCnYisNNZjmcIj+Rixn0uhZNY3G1vzlgdVdLygeRSuFjkmnZk6WwvGzUWpKfnG0e/NUySM3mVi59hAA== dependencies: - "@vue/shared" "3.0.11" + "@vue/shared" "3.2.6" -"@vue/runtime-core@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.11.tgz#c52dfc6acf3215493623552c1c2919080c562e44" - integrity sha512-87XPNwHfz9JkmOlayBeCCfMh9PT2NBnv795DSbi//C/RaAnc/bGZgECjmkD7oXJ526BZbgk9QZBPdFT8KMxkAg== +"@vue/runtime-core@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.6.tgz#376baeef7fe02a62377d46d0d0a8ab9510db1d8e" + integrity sha512-3mqtgpj/YSGFxtvTufSERRApo92B16JNNxz9p+5eG6PPuqTmuRJz214MqhKBEgLEAIQ6R6YCbd83ZDtjQnyw2g== dependencies: - "@vue/reactivity" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/reactivity" "3.2.6" + "@vue/shared" "3.2.6" -"@vue/runtime-dom@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.11.tgz#7a552df21907942721feb6961c418e222a699337" - integrity sha512-jm3FVQESY3y2hKZ2wlkcmFDDyqaPyU3p1IdAX92zTNeCH7I8zZ37PtlE1b9NlCtzV53WjB4TZAYh9yDCMIEumA== +"@vue/runtime-dom@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.6.tgz#0f74dbca84d56c222fbfbd53415b260386859a3b" + integrity sha512-fq33urnP0BNCGm2O3KCzkJlKIHI80C94HJ4qDZbjsTtxyOn5IHqwKSqXVN3RQvO6epcQH+sWS+JNwcNDPzoasg== dependencies: - "@vue/runtime-core" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/runtime-core" "3.2.6" + "@vue/shared" "3.2.6" csstype "^2.6.8" -"@vue/shared@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77" - integrity sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA== +"@vue/shared@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.6.tgz#2c22bae88fe2b7b59fa68a9c9c4cd60bae2c1794" + integrity sha512-uwX0Qs2e6kdF+WmxwuxJxOnKs/wEkMArtYpHSm7W+VY/23Tl8syMRyjnzEeXrNCAP0/8HZxEGkHJsjPEDNRuHw== "@webassemblyjs/ast@1.9.0": version "1.9.0" @@ -1108,6 +1108,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + JSONStream@^1.0.3: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -1895,6 +1900,11 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2167,6 +2177,17 @@ cross-spawn@^4: lru-cache "^4.0.1" which "^1.2.9" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2618,7 +2639,7 @@ estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== -estree-walker@^2.0.1: +estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -2807,6 +2828,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + 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" @@ -2880,6 +2908,15 @@ fs-extra@9.0.0: jsonfile "^6.0.1" universalify "^1.0.0" +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.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" @@ -3351,6 +3388,13 @@ is-callable@^1.1.4, is-callable@^1.2.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + is-core-module@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.3.0.tgz#d341652e3408bca69c4671b79a0954a3d349f887" @@ -3395,6 +3439,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-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" @@ -3510,6 +3559,13 @@ is-wsl@^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: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + 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" @@ -3724,6 +3780,13 @@ json5@^2.1.0, json5@^2.1.2: dependencies: minimist "^1.2.5" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -3777,6 +3840,13 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + labeled-stream-splicer@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" @@ -4179,6 +4249,11 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -4404,6 +4479,14 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + os-browserify@^0.3.0, os-browserify@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -4414,6 +4497,11 @@ os-homedir@^1.0.1: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +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= + outpipe@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" @@ -4535,6 +4623,25 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +patch-package@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" + integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + path-browserify@0.0.1, path-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -4560,6 +4667,11 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -5225,6 +5337,13 @@ shasum@^1.0.0: json-stable-stringify "~0.0.0" sha.js "~2.4.4" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -5232,6 +5351,11 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -5252,6 +5376,11 @@ simple-concat@^1.0.0: resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -5682,6 +5811,13 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -5849,6 +5985,11 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" @@ -5972,14 +6113,14 @@ vue-loader@16.2.0: hash-sum "^2.0.0" loader-utils "^2.0.0" -vue@3.0.11: - version "3.0.11" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f" - integrity sha512-3/eUi4InQz8MPzruHYSTQPxtM3LdZ1/S/BvaU021zBnZi0laRUyH6pfuE4wtUeLvI8wmUNwj5wrZFvbHUXL9dw== +vue@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.6.tgz#c71445078751f458648fd8fb3a2da975507d03d2" + integrity sha512-Zlb3LMemQS3Xxa6xPsecu45bNjr1hxO8Bh5FUmE0Dr6Ot0znZBKiM47rK6O7FTcakxOnvVN+NTXWJF6u8ajpCQ== dependencies: - "@vue/compiler-dom" "3.0.11" - "@vue/runtime-dom" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/compiler-dom" "3.2.6" + "@vue/runtime-dom" "3.2.6" + "@vue/shared" "3.2.6" watchify@3.11.1: version "3.11.1" @@ -6006,8 +6147,10 @@ watchpack@^1.7.4: resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== dependencies: + chokidar "^3.4.1" graceful-fs "^4.1.2" neo-async "^2.5.0" + watchpack-chokidar2 "^2.0.1" optionalDependencies: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1" @@ -6020,7 +6163,7 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@4.46.0: +webpack@^4.44.2: version "4.46.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== diff --git a/npm/vue/examples/vue-cli/README.md b/npm/vue/examples/vue-cli/README.md index 13a66aaf10..e3e7d015ee 100644 --- a/npm/vue/examples/vue-cli/README.md +++ b/npm/vue/examples/vue-cli/README.md @@ -22,7 +22,7 @@ We need to install: ### Configure Cypress -To setup any Cypress runner, the standard way is to create a `cypress.json` file at the root of your project. Checkout [the docs](https://docs.cypress.io/guides/references/configuration) to know the extend of your options. +To setup any Cypress runner, the standard way is to create a `cypress.json` file at the root of your project. Checkout [the docs](https://on.cypress.io/guides/configuration) to know the extend of your options. Here is the `cypress.json` file at work in this project: @@ -36,9 +36,6 @@ Here is the `cypress.json` file at work in this project: "supportFile": false, // Tell Cypress how to recognize spec files "testFiles": "**/*spec.js", - // All the component test files are - // located in this directory and its sub-directory - "componentFolder": "src" } ``` @@ -86,4 +83,4 @@ const modifiedWebpackConfig = { return x.constructor.name !== 'HtmlPwaPlugin' }), } -``` \ No newline at end of file +``` diff --git a/npm/vue/examples/vue-cli/cypress.config.js b/npm/vue/examples/vue-cli/cypress.config.js new file mode 100644 index 0000000000..7a29588805 --- /dev/null +++ b/npm/vue/examples/vue-cli/cypress.config.js @@ -0,0 +1,28 @@ +const { devServer } = require('@cypress/webpack-dev-server') +const webpackConfig = require('@vue/cli-service/webpack.config') + +module.exports = { + 'video': false, + 'fixturesFolder': false, + 'component': { + devServer, + devServerConfig: { + // HtmlPwaPlugin is coupled to a hook in HtmlWebpackPlugin + // that was deprecated after 3.x. We currently only support + // HtmlWebpackPlugin 4.x and 5.x. + // TODO: Figure out how to deal with 2 major versions old HtmlWebpackPlugin + // which is still in widespread usage. + webpackConfig: { + ...webpackConfig, + plugins: (webpackConfig.plugins || []).filter((x) => { + return x.constructor.name !== 'HtmlPwaPlugin' + }), + }, + }, + setupNodeEvents (on, config) { + require('@cypress/code-coverage/task')(on, config) + + return config + }, + }, +} diff --git a/npm/vue/examples/vue-cli/cypress.json b/npm/vue/examples/vue-cli/cypress.json deleted file mode 100644 index 7d2950c001..0000000000 --- a/npm/vue/examples/vue-cli/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "video": false, - "fixturesFolder": false, - "testFiles": "**/*spec.js", - "componentFolder": "src" -} \ No newline at end of file diff --git a/npm/vue/examples/vue-cli/cypress/plugins/index.js b/npm/vue/examples/vue-cli/cypress/plugins/index.js deleted file mode 100644 index 400d19d0f6..0000000000 --- a/npm/vue/examples/vue-cli/cypress/plugins/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -const { startDevServer } = require('@cypress/webpack-dev-server') -const webpackConfig = require('@vue/cli-service/webpack.config') - -/** - * @type Cypress.PluginConfig - */ -module.exports = (on, config) => { - on('dev-server:start', (options) => { - // HtmlPwaPlugin is coupled to a hook in HtmlWebpackPlugin - // that was deprecated after 3.x. We currently only support - // HtmlWebpackPlugin 4.x and 5.x. - // TODO: Figure out how to deal with 2 major versions old HtmlWebpackPlugin - // which is still in widespread usage. - const modifiedWebpackConfig = { - ...webpackConfig, - plugins: (webpackConfig.plugins || []).filter((x) => { - return x.constructor.name !== 'HtmlPwaPlugin' - }), - } - - return startDevServer({ - options, - webpackConfig: modifiedWebpackConfig, - }) - }) - - require('@cypress/code-coverage/task')(on, config) - - return config -} diff --git a/npm/vue/examples/vue-cli/cypress/support/component-index.html b/npm/vue/examples/vue-cli/cypress/support/component-index.html new file mode 100644 index 0000000000..ac6e79fd83 --- /dev/null +++ b/npm/vue/examples/vue-cli/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + \ No newline at end of file diff --git a/npm/vue/examples/vue-cli/cypress/support/index.js b/npm/vue/examples/vue-cli/cypress/support/component.js similarity index 100% rename from npm/vue/examples/vue-cli/cypress/support/index.js rename to npm/vue/examples/vue-cli/cypress/support/component.js diff --git a/npm/vue/examples/vue-cli/package.json b/npm/vue/examples/vue-cli/package.json index b7a4fa4e60..682c216973 100644 --- a/npm/vue/examples/vue-cli/package.json +++ b/npm/vue/examples/vue-cli/package.json @@ -5,15 +5,16 @@ "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", - "cy:open": "node ../../../../scripts/cypress open-ct", - "test": "node ../../../../scripts/cypress run-ct", + "cy:open": "node ../../../../scripts/cypress open --component", + "test": "node ../../../../scripts/cypress run --component", "report:coverage": "nyc report", - "coveralls": "nyc report --reporter=text-lcov | coveralls" + "coveralls": "nyc report --reporter=text-lcov | coveralls", + "postinstall": "patch-package" }, "dependencies": { "core-js": "^3.6.5", "register-service-worker": "^1.7.1", - "vue": "^3.0.11" + "vue": "3.2.31" }, "devDependencies": { "@cypress/code-coverage": "^3.9.5", @@ -24,6 +25,7 @@ "babel-plugin-istanbul": "~6.0.0", "mocha-junit-reporter": "^2.0.0", "mocha-multi-reporters": "^1.5.1", + "patch-package": "6.4.7", "vue-template-compiler": "^2.6.11" } } diff --git a/npm/vue/examples/vue-cli/patches/@cypress+code-coverage+3.9.5.patch b/npm/vue/examples/vue-cli/patches/@cypress+code-coverage+3.9.5.patch new file mode 100644 index 0000000000..f905d3a539 --- /dev/null +++ b/npm/vue/examples/vue-cli/patches/@cypress+code-coverage+3.9.5.patch @@ -0,0 +1,45 @@ +diff --git a/node_modules/@cypress/code-coverage/support-utils.js b/node_modules/@cypress/code-coverage/support-utils.js +index 31e00ee..0c56908 100644 +--- a/node_modules/@cypress/code-coverage/support-utils.js ++++ b/node_modules/@cypress/code-coverage/support-utils.js +@@ -10,7 +10,7 @@ const filterSpecsFromCoverage = (totalCoverage, config = Cypress.config) => { + const integrationFolder = config('integrationFolder') + /** @type {string} Cypress run-time config has test files string pattern */ + // @ts-ignore +- const testFilePattern = config('testFiles') ++ const testFilePattern = config('specPattern') + + // test files chould be: + // wild card string "**/*.*" (default) +diff --git a/node_modules/@cypress/code-coverage/support.js b/node_modules/@cypress/code-coverage/support.js +index c99ceb2..f51ce4e 100644 +--- a/node_modules/@cypress/code-coverage/support.js ++++ b/node_modules/@cypress/code-coverage/support.js +@@ -37,7 +37,6 @@ const logMessage = (s) => { + * If there are more files loaded from support folder, also removes them + */ + const filterSupportFilesFromCoverage = (totalCoverage) => { +- const integrationFolder = Cypress.config('integrationFolder') + const supportFile = Cypress.config('supportFile') + + /** @type {string} Cypress run-time config has the support folder string */ +@@ -50,16 +49,9 @@ const filterSupportFilesFromCoverage = (totalCoverage) => { + isSupportFile(filename) + ) + +- // check the edge case +- // if we have files from support folder AND the support folder is not same +- // as the integration, or its prefix (this might remove all app source files) +- // then remove all files from the support folder +- if (!integrationFolder.startsWith(supportFolder)) { +- // remove all covered files from support folder +- coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => +- filename.startsWith(supportFolder) +- ) +- } ++ coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => ++ filename.startsWith(supportFolder) ++ ) + return coverage + } + diff --git a/npm/vue/examples/vue-cli/src/App.vue b/npm/vue/examples/vue-cli/src/App.vue index 55df315325..2afc9c94bd 100644 --- a/npm/vue/examples/vue-cli/src/App.vue +++ b/npm/vue/examples/vue-cli/src/App.vue @@ -1,7 +1,10 @@ @@ -11,8 +14,8 @@ import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { - HelloWorld - } + HelloWorld, + }, } diff --git a/npm/vue/examples/vue-cli/src/components/HelloWorld.spec.js b/npm/vue/examples/vue-cli/src/components/HelloWorld.cy.js similarity index 100% rename from npm/vue/examples/vue-cli/src/components/HelloWorld.spec.js rename to npm/vue/examples/vue-cli/src/components/HelloWorld.cy.js diff --git a/npm/vue/examples/vue-cli/src/components/HelloWorld.vue b/npm/vue/examples/vue-cli/src/components/HelloWorld.vue index 7fd2dc572b..3c51d78f2d 100644 --- a/npm/vue/examples/vue-cli/src/components/HelloWorld.vue +++ b/npm/vue/examples/vue-cli/src/components/HelloWorld.vue @@ -4,27 +4,97 @@

For a guide and recipes on how to configure / customize this project,
check out the - vue-cli documentation. + vue-cli documentation.

Installed CLI Plugins

Essential Links

Ecosystem

@@ -33,8 +103,11 @@ export default { name: 'HelloWorld', props: { - msg: String - } + msg: { + type: String, + default: '', + }, + }, } diff --git a/npm/vue/examples/vue-cli/yarn.lock b/npm/vue/examples/vue-cli/yarn.lock index ee145fe9f1..da43322279 100644 --- a/npm/vue/examples/vue-cli/yarn.lock +++ b/npm/vue/examples/vue-cli/yarn.lock @@ -283,6 +283,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@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.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -325,7 +330,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.13": +"@babel/parser@^7.12.13", "@babel/parser@^7.13.13": version "7.13.13" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df" integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw== @@ -335,6 +340,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== +"@babel/parser@^7.15.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" @@ -1110,7 +1120,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.13", "@babel/types@^7.13.14", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.13", "@babel/types@^7.13.14", "@babel/types@^7.4.4": version "7.13.14" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ== @@ -1127,6 +1137,14 @@ "@babel/helper-validator-identifier" "^7.12.11" to-fast-properties "^2.0.0" +"@babel/types@^7.15.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + "@cypress/browserify-preprocessor@3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz#ab86335b0c061d11f5ad7df03f06b1877b836f71" @@ -1681,24 +1699,24 @@ semver "^6.1.0" strip-ansi "^6.0.0" -"@vue/compiler-core@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.11.tgz#5ef579e46d7b336b8735228758d1c2c505aae69a" - integrity sha512-6sFj6TBac1y2cWCvYCA8YzHJEbsVkX7zdRs/3yK/n1ilvRqcn983XvpBbnN3v4mZ1UiQycTvOiajJmOgN9EVgw== +"@vue/compiler-core@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.6.tgz#7162bb0670273f04566af0d353009187ab577915" + integrity sha512-vbwnz7+OhtLO5p5i630fTuQCL+MlUpEMTKHuX+RfetQ+3pFCkItt2JUH+9yMaBG2Hkz6av+T9mwN/acvtIwpbw== dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.0.11" - estree-walker "^2.0.1" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" + "@vue/shared" "3.2.6" + estree-walker "^2.0.2" source-map "^0.6.1" -"@vue/compiler-dom@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.11.tgz#b15fc1c909371fd671746020ba55b5dab4a730ee" - integrity sha512-+3xB50uGeY5Fv9eMKVJs2WSRULfgwaTJsy23OIltKgMrynnIj8hTYY2UL97HCoz78aDw1VDXdrBQ4qepWjnQcw== +"@vue/compiler-dom@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.6.tgz#3764d7fe1a696e39fb2a3c9d638da0749e369b2d" + integrity sha512-+a/3oBAzFIXhHt8L5IHJOTP4a5egzvpXYyi13jR7CUYOR1S+Zzv7vBWKYBnKyJLwnrxTZnTQVjeHCgJq743XKg== dependencies: - "@vue/compiler-core" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/compiler-core" "3.2.6" + "@vue/shared" "3.2.6" "@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.1.2": version "3.2.0" @@ -1721,34 +1739,34 @@ resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz#ceb924b4ecb3b9c43871c7a429a02f8423e621ab" integrity sha512-LIZMuJk38pk9U9Ur4YzHjlIyMuxPlACdBIHH9/nGYVTsaGKOSnSuELiE8vS9wa+dJpIYspYUOqk+L1Q4pgHQHQ== -"@vue/reactivity@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.11.tgz#07b588349fd05626b17f3500cbef7d4bdb4dbd0b" - integrity sha512-SKM3YKxtXHBPMf7yufXeBhCZ4XZDKP9/iXeQSC8bBO3ivBuzAi4aZi0bNoeE2IF2iGfP/AHEt1OU4ARj4ao/Xw== +"@vue/reactivity@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.6.tgz#b8993fa6f48545178e588e25a9c9431a1c1b7d50" + integrity sha512-8vIDD2wpCnYisNNZjmcIj+Rixn0uhZNY3G1vzlgdVdLygeRSuFjkmnZk6WwvGzUWpKfnG0e/NUySM3mVi59hAA== dependencies: - "@vue/shared" "3.0.11" + "@vue/shared" "3.2.6" -"@vue/runtime-core@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.11.tgz#c52dfc6acf3215493623552c1c2919080c562e44" - integrity sha512-87XPNwHfz9JkmOlayBeCCfMh9PT2NBnv795DSbi//C/RaAnc/bGZgECjmkD7oXJ526BZbgk9QZBPdFT8KMxkAg== +"@vue/runtime-core@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.6.tgz#376baeef7fe02a62377d46d0d0a8ab9510db1d8e" + integrity sha512-3mqtgpj/YSGFxtvTufSERRApo92B16JNNxz9p+5eG6PPuqTmuRJz214MqhKBEgLEAIQ6R6YCbd83ZDtjQnyw2g== dependencies: - "@vue/reactivity" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/reactivity" "3.2.6" + "@vue/shared" "3.2.6" -"@vue/runtime-dom@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.11.tgz#7a552df21907942721feb6961c418e222a699337" - integrity sha512-jm3FVQESY3y2hKZ2wlkcmFDDyqaPyU3p1IdAX92zTNeCH7I8zZ37PtlE1b9NlCtzV53WjB4TZAYh9yDCMIEumA== +"@vue/runtime-dom@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.6.tgz#0f74dbca84d56c222fbfbd53415b260386859a3b" + integrity sha512-fq33urnP0BNCGm2O3KCzkJlKIHI80C94HJ4qDZbjsTtxyOn5IHqwKSqXVN3RQvO6epcQH+sWS+JNwcNDPzoasg== dependencies: - "@vue/runtime-core" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/runtime-core" "3.2.6" + "@vue/shared" "3.2.6" csstype "^2.6.8" -"@vue/shared@3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77" - integrity sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA== +"@vue/shared@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.6.tgz#2c22bae88fe2b7b59fa68a9c9c4cd60bae2c1794" + integrity sha512-uwX0Qs2e6kdF+WmxwuxJxOnKs/wEkMArtYpHSm7W+VY/23Tl8syMRyjnzEeXrNCAP0/8HZxEGkHJsjPEDNRuHw== "@vue/web-component-wrapper@^1.2.0": version "1.3.0" @@ -1910,6 +1928,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + JSONStream@^1.0.3: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -3002,6 +3025,11 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -3417,7 +3445,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -4143,7 +4171,7 @@ estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== -estree-walker@^2.0.1: +estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -4469,6 +4497,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + 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" @@ -5333,6 +5368,13 @@ is-callable@^1.1.4, is-callable@^1.2.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + is-color-stop@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" @@ -5851,6 +5893,13 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + labeled-stream-splicer@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" @@ -6726,6 +6775,14 @@ open@^6.3.0: dependencies: is-wsl "^1.1.0" +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + opener@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -6762,6 +6819,11 @@ os-browserify@^0.3.0, os-browserify@~0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= +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= + outpipe@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" @@ -6918,6 +6980,25 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +patch-package@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" + integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + path-browserify@0.0.1, path-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -8737,6 +8818,13 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -9177,14 +9265,14 @@ vue-template-es2015-compiler@^1.9.0: resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== -vue@^3.0.11: - version "3.0.11" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f" - integrity sha512-3/eUi4InQz8MPzruHYSTQPxtM3LdZ1/S/BvaU021zBnZi0laRUyH6pfuE4wtUeLvI8wmUNwj5wrZFvbHUXL9dw== +vue@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.6.tgz#c71445078751f458648fd8fb3a2da975507d03d2" + integrity sha512-Zlb3LMemQS3Xxa6xPsecu45bNjr1hxO8Bh5FUmE0Dr6Ot0znZBKiM47rK6O7FTcakxOnvVN+NTXWJF6u8ajpCQ== dependencies: - "@vue/compiler-dom" "3.0.11" - "@vue/runtime-dom" "3.0.11" - "@vue/shared" "3.0.11" + "@vue/compiler-dom" "3.2.6" + "@vue/runtime-dom" "3.2.6" + "@vue/shared" "3.2.6" watchify@3.11.1: version "3.11.1" @@ -9211,8 +9299,10 @@ watchpack@^1.7.4: resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== dependencies: + chokidar "^3.4.1" graceful-fs "^4.1.2" neo-async "^2.5.0" + watchpack-chokidar2 "^2.0.1" optionalDependencies: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1" diff --git a/npm/vue/package.json b/npm/vue/package.json index 2b8aece08a..7c1efda0ac 100644 --- a/npm/vue/package.json +++ b/npm/vue/package.json @@ -4,10 +4,11 @@ "description": "Browser-based Component Testing for Vue.js with Cypress.io โœŒ๏ธ๐ŸŒฒ", "main": "dist/cypress-vue.cjs.js", "scripts": { - "build": "rimraf dist && rollup -c rollup.config.js", "build-prod": "yarn build", - "cy:open": "node ../../scripts/cypress.js open-ct --project ${PWD}", - "cy:run": "node ../../scripts/cypress.js run-ct --project ${PWD}", + "cy:open": "node ../../scripts/cypress.js open --component --project ${PWD}", + "cy:run": "node ../../scripts/cypress.js run --component --project ${PWD}", + "build": "rimraf dist && rollup -c rollup.config.js", + "postbuild": "node ../../scripts/sync-exported-npm-with-cli.js", "typecheck": "vue-tsc --noEmit", "test": "yarn cy:run", "watch": "yarn build --watch --watch.exclude ./dist/**/*", @@ -15,8 +16,7 @@ "test:ci:ct": "node ../../scripts/run-ct-examples.js --examplesList=./examples.env" }, "dependencies": { - "@cypress/mount-utils": "0.0.0-development", - "@vue/test-utils": "^2.0.0-rc.10" + "@vue/test-utils": "2.0.0-rc.19" }, "devDependencies": { "@babel/core": "7.9.0", @@ -24,13 +24,14 @@ "@babel/preset-env": "7.9.5", "@babel/preset-typescript": "7.10.1", "@cypress/code-coverage": "3.8.1", + "@cypress/mount-utils": "0.0.0-development", "@cypress/webpack-dev-server": "0.0.0-development", "@intlify/vue-i18n-loader": "2.0.0-rc.1", "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-node-resolve": "^11.1.1", "@vue/cli-plugin-babel": "~4.4.0", "@vue/cli-service": "~4.4.0", - "@vue/compiler-sfc": "3.1.5", + "@vue/compiler-sfc": "3.2.31", "axios": "0.21.2", "babel-loader": "8.1.0", "babel-plugin-istanbul": "^6.0.0", @@ -38,7 +39,7 @@ "css-loader": "3.4.2", "cypress": "0.0.0-development", "debug": "^4.3.2", - "eslint-plugin-vue": "^6.2.2", + "eslint-plugin-vue": "8.5.0", "find-webpack": "2.1.0", "mocha": "7.1.1", "mocha-junit-reporter": "^2.0.0", @@ -48,14 +49,15 @@ "rollup-plugin-typescript2": "^0.29.0", "tailwindcss": "1.1.4", "typescript": "^4.2.3", - "vue": "3.1.5", + "vue": "3.2.31", + "vue-eslint-parser": "7.11.0", "vue-i18n": "9.0.0-rc.6", "vue-loader": "16.1.2", "vue-router": "^4.0.0", "vue-style-loader": "4.1.2", - "vue-tsc": "0.2.2", + "vue-tsc": "^0.3.0", "vuex": "^4.0.0", - "webpack": "4.42.0" + "webpack": "^4.44.2" }, "peerDependencies": { "@cypress/webpack-dev-server": "*", diff --git a/npm/vue/rollup.config.js b/npm/vue/rollup.config.js index 1ea32749f4..38c3018cb0 100644 --- a/npm/vue/rollup.config.js +++ b/npm/vue/rollup.config.js @@ -22,9 +22,6 @@ function createEntry (options) { input, external: [ 'vue', - '@vue/test-utils', - '@cypress/mount-utils', - '@cypress/webpack-dev-server', ], plugins: [ resolve({ preferBuiltins: true }), commonjs(), @@ -36,7 +33,6 @@ function createEntry (options) { format, globals: { vue: 'Vue', - '@vue/test-utils': 'VueTestUtils', }, exports: 'auto', }, diff --git a/npm/vue/src/index.ts b/npm/vue/src/index.ts index 2476ba70c2..8afb1f4c94 100644 --- a/npm/vue/src/index.ts +++ b/npm/vue/src/index.ts @@ -8,7 +8,7 @@ import { MountingOptions, VueWrapper, mount as VTUmount } from '@vue/test-utils' import { injectStylesBeforeElement, StyleOptions, - ROOT_ID, + getContainerEl, setupHooks, } from '@cypress/mount-utils' @@ -28,7 +28,7 @@ declare global { } } -type CyMountOptions = Omit, 'attachTo'> & { +export type CyMountOptions = Omit, 'attachTo'> & { log?: boolean /** * @deprecated use vue-test-utils `global` instead @@ -43,7 +43,7 @@ let initialInnerHtml = '' Cypress.on('run:start', () => { // `mount` is designed to work with component testing only. - // it assumes ROOT_ID exists, which is not the case in e2e. + // it assumes ROOT_SELECTOR exists, which is not the case in e2e. // if the user registers a custom command that imports `cypress/vue`, // this event will be registered and cause an error when the user // launches e2e (since it's common to use Cypress for both CT and E2E. @@ -55,13 +55,7 @@ Cypress.on('run:start', () => { initialInnerHtml = document.head.innerHTML Cypress.on('test:before:run', () => { Cypress.vueWrapper?.unmount() - // @ts-ignore - const document: Document = cy.state('document') - let el = document.getElementById(ROOT_ID) - - if (!el) { - throw Error(`no element found at query #${ROOT_ID}. Please use the mount utils to mount it properly`) - } + const el = getContainerEl() el.innerHTML = '' document.head.innerHTML = initialInnerHtml @@ -238,11 +232,7 @@ export function mount ( // @ts-ignore const document: Document = cy.state('document') - let el = document.getElementById(ROOT_ID) - - if (!el) { - throw Error(`no element found at query #${ROOT_ID}. Please use the mount utils to mount it properly`) - } + const el = getContainerEl() injectStylesBeforeElement(options, document, el) diff --git a/npm/vue2/.eslintrc b/npm/vue2/.eslintrc new file mode 100644 index 0000000000..220212842e --- /dev/null +++ b/npm/vue2/.eslintrc @@ -0,0 +1,17 @@ +{ + "plugins": [ + "cypress" + ], + "extends": [ + "plugin:@cypress/dev/tests" + ], + "env": { + "cypress/globals": true + }, + "rules": { + "mocha/no-global-tests": "off", + "no-unused-vars": "off", + "no-console": "off", + "@typescript-eslint/no-unused-vars": "off" + } +} diff --git a/npm/vue2/.npmrc b/npm/vue2/.npmrc new file mode 100644 index 0000000000..6778d0857e --- /dev/null +++ b/npm/vue2/.npmrc @@ -0,0 +1,4 @@ +registry=http://registry.npmjs.org/ +save-exact=true +progress=false +package-lock=true diff --git a/npm/vue2/.releaserc.js b/npm/vue2/.releaserc.js new file mode 100644 index 0000000000..4cb1091bc4 --- /dev/null +++ b/npm/vue2/.releaserc.js @@ -0,0 +1,7 @@ +module.exports = { + ...require('../../.releaserc.base'), + branches: [ + // this one releases v3 on master on the latest channel + 'master', + ], +} diff --git a/npm/vue2/CHANGELOG.md b/npm/vue2/CHANGELOG.md new file mode 100644 index 0000000000..a1e9004f74 --- /dev/null +++ b/npm/vue2/CHANGELOG.md @@ -0,0 +1,5 @@ +# @cypress/vue2-v1.0.0 (2021-06-17) + +### Features + +* Split out as separate package from `@cypress/vue`, based on the `npm/vue/v2` branch. diff --git a/npm/vue2/README.md b/npm/vue2/README.md new file mode 100644 index 0000000000..5777a0a015 --- /dev/null +++ b/npm/vue2/README.md @@ -0,0 +1,693 @@ +# @cypress/vue2 + +[![NPM][npm-icon] ][npm-url] + +[![semantic-release][semantic-image] ][semantic-url] + +> Browser-based Component Testing for Vue.js 2.x with the Open-Source [Cypress.io](https://www.cypress.io/) Test Runner โœŒ๏ธ๐ŸŒฒ +> +**โœจ New** We're growing the Cypress Community Discord. We have dedicated sections on Component Testing. ๐Ÿ‘‰ [Join now](https://discord.com/invite/TmzTGUW) and let's chat! + +**Jump to:** [Comparison](#comparison), [Blog posts](#blog-posts), Examples: [basic](#basic-examples), [advanced](#advanced-examples), [full](#full-examples), [external](#external-examples), [Code coverage](#code-coverage), [Development](#development) + +### What is @cypress/vue2? +This package allows you to use the [Cypress](https://www.cypress.io/) test runner to mount and test your Vue 2 components within Cypress. It is built on top of the [Vue Test Utils](https://github.com/vuejs/vue-test-utils) package. + +![Example component test](images/dynamic.gif) + +### How is this different from Vue Test Utils? +It uses [Vue Test Utils](https://github.com/vuejs/vue-test-utils) under the hood. This is more of a replacement for node-based testing than it is replacing Vue Test Utils and its API. Instead of running your tests in node (using Jest or Mocha), the Cypress Component Testing Library runs each component in the **real browser** with full power of the Cypress Framework: [live GUI, full API, screen recording, CI support, cross-platform](https://www.cypress.io/features/). One benefit to using Cypress instead of a node-based runner is that limitations of Vue Test Utils in Node (e.g. manually awaiting Vue's internal event loop) are hidden from the user due to Cypress's retry-ability logic. + +- If you like using `@testing-library/vue`, you can use `@testing-library/cypress` for the same `findBy`, `queryBy` commands, see one of the examples in the list below + +### How is this different from @cypress/vue? +Cypress packages the current version of Vue under @cypress/vue, and older versions under separate package names. Use [@cypress/vue](cypress-vue-npm-url) if you're up to date, and this package if you're still using vue@2. + +## Installation + +- Requires Cypress v7.0.0 or later +- Requires [Node](https://nodejs.org/en/) version 12 or above +- Requires Vue 2.x. If you are using Vue 3.0.0 or later, you want [@cypress/vue](cypress-vue-npm-url) instead. +- Supports webpack-based projects, vite in alpha, if you would like us to support another, please [create an issue](https://github.com/cypress-io/cypress/issues/new?assignees=&labels=npm:%20@cypress/vue2&template=3-feature.md) or, if an issue already exists subscribe to it. + +Now you are ready to install. + +### Manual Installation + +Using [@cypress/webpack-dev-server](https://github.com/cypress-io/cypress-webpack-preprocessor#readme) and [vue-loader](https://github.com/vuejs/vue-loader). + +```js +// cypress/plugins/index.js +const webpack = require('@cypress/webpack-dev-server') +const webpackOptions = { + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + }, + ], + }, +} + +const options = { + // send in the options from your webpack.config.js, so it works the same + // as your app's code + webpackOptions, + watchOptions: {}, +} + +module.exports = (on) => { + on('dev-server:start', webpack(options)) +} +``` + +Install dev dependencies + +```shell +npm i -D @cypress/webpack-dev-server \ + vue-loader vue-template-compiler css-loader +``` + +And write a test + +```js +import Hello from '../../components/Hello.vue' +import { mountCallback } from '@cypress/vue2' + +describe('Hello.vue', () => { + beforeEach(mountCallback(Hello)) + + it('shows hello', () => { + cy.contains('Hello World!') + }) +}) +``` + +## Usage and Examples + +```js +// components/HelloWorld.spec.js +import { mount } from '@cypress/vue2' +import { HelloWorld } from './HelloWorld.vue' +describe('HelloWorld component', () => { + it('works', () => { + mount(HelloWorld) + // now use standard Cypress commands + cy.contains('Hello World!').should('be.visible') + }) +}) +``` + +### Options + +You can pass additional styles, css files and external stylesheets to load, see [docs/styles.md](./docs/styles.md) for full list. + +```js +import Todo from './Todo.vue' +const todo = { + id: '123', + title: 'Write more tests', +} + +mount(Todo, { + propsData: { todo }, + stylesheets: [ + 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css', + ], +}) +``` + +See examples below for details. + +### Global Vue Options + +You can pass extensions (global components, mixins, modules to use) +when mounting Vue component. Use `{ extensions: { ... }}` object inside +the `options`. + +- `components` - object of 'id' and components to register globally, see [Components](cypress/component/basic/components) example +- `use` (alias `plugins`) - list of plugins, see [Plugins](cypress/component/basic/plugins) +- `mixin` (alias `mixins`) - list of global mixins, see [Mixins](cypress/component/basic/mixins) example +- `filters` - hash of global filters, see [Filters](cypress/component/basic/filters) example + +### intro example + +Take a look at the first Vue v2 example: +[Declarative Rendering](https://vuejs.org/v2/guide/#Declarative-Rendering). +The code is pretty simple + +```html +
+ {{ message }} +
+``` + +```js +var app = new Vue({ + el: '#app', + data() { + return { message: 'Hello Vue!' } + }, +}) +``` + +It shows the message when running in the browser + +``` +Hello Vue! +``` + +Let's test it in [Cypress.io][cypress.io] (for the current version see +[cypress/integration/spec.js](cypress/integration/spec.js)). + +```js +import { mountCallback } from '@cypress/vue2' + +describe('Declarative rendering', () => { + // Vue code from https://vuejs.org/v2/guide/#Declarative-Rendering + const template = ` +
+ {{ message }} +
+ ` + + const data = { + message: 'Hello Vue!', + } + + // that's all you need to do + beforeEach(mountCallback({ template, data })) + + it('shows hello', () => { + cy.contains('Hello Vue!') + }) + + it('changes message if data changes', () => { + // mounted Vue instance is available under Cypress.vue + Cypress.vue.message = 'Vue rocks!' + cy.contains('Vue rocks!') + }) +}) +``` + +Fire up Cypress test runner and have real browser (Electron, Chrome) load +Vue and mount your test code and be able to interact with the instance through +the reference `Cypress.vue.$data` and via GUI. The full power of the +[Cypress API](https://on.cypress.io/api) is available. + +![Hello world tested](images/spec.png) + +### list example + +There is a list example next in the Vue docs. + +```html +
+
    +
  1. + {{ todo.text }} +
  2. +
+
+``` + +```js +var app4 = new Vue({ + el: '#app-4', + data: { + todos: [ + { text: 'Learn JavaScript' }, + { text: 'Learn Vue' }, + { text: 'Build something awesome' }, + ], + }, +}) +``` + +Let's test it. Simple. + +```js +import { mountCallback } from '@cypress/vue2' + +describe('Declarative rendering', () => { + // List example from https://vuejs.org/v2/guide/#Declarative-Rendering + const template = ` +
    +
  1. + {{ todo.text }} +
  2. +
+ ` + + function data() { + return { + todos: [ + { text: 'Learn JavaScript' }, + { text: 'Learn Vue' }, + { text: 'Build something awesome' }, + ], + } + } + + beforeEach(mountCallback({ template, data })) + + it('shows 3 items', () => { + cy.get('li').should('have.length', 3) + }) + + it('can add an item', () => { + Cypress.vue.todos.push({ text: 'Test using Cypress' }) + cy.get('li').should('have.length', 4) + }) +}) +``` + +![List tested](images/list-spec.png) + +### Handling User Input + +The next section in the Vue docs starts with [reverse message example](https://vuejs.org/v2/guide/#Handling-User-Input). + +```html +
+

{{ message }}

+ +
+``` + +```js +var app5 = new Vue({ + el: '#app-5', + data: { + message: 'Hello Vue.js!', + }, + methods: { + reverseMessage: function () { + this.message = this.message.split('').reverse().join('') + }, + }, +}) +``` + +We can write the test the same way + +```js +import { mountCallback } from '@cypress/vue2' + +describe('Handling User Input', () => { + // Example from https://vuejs.org/v2/guide/#Handling-User-Input + const template = ` +
+

{{ message }}

+ +
+ ` + + function data() { + return { message: 'Hello Vue.js!' } + } + + const methods = { + reverseMessage: function () { + this.message = this.message.split('').reverse().join('') + }, + } + + beforeEach(mountCallback({ template, data, methods })) + + it('reverses text', () => { + cy.contains('Hello Vue') + cy.get('button').click() + cy.contains('!sj.euV olleH') + }) +}) +``` + +Take a look at the video of the test. When you hover over the `CLICK` step +the test runner is showing _before_ and _after_ DOM snapshots. Not only that, +the application is fully functioning, you can interact with the application +because it is really running! + +![Reverse input](images/reverse-spec.gif) + + + +### Component example + +Let us test a complex example. Let us test a [single file Vue component](https://vuejs.org/v2/guide/single-file-components.html). Here is the [Hello.vue](Hello.vue) file + +```vue + + + + + +``` + +**note** to learn how to load Vue component files in Cypress, see +[Bundling](#bundling) section. + +Do you want to interact with the component? Go ahead! Do you want +to have multiple components? No problem! + +```js +import Hello from '../../components/Hello.vue' +import { mountCallback } from '@cypress/vue2' +describe('Several components', () => { + const template = ` +
+ + + +
+ ` + const components = { + hello: Hello, + } + beforeEach(mountCallback({ template, components })) + + it('greets the world 3 times', () => { + cy.get('p').should('have.length', 3) + }) +}) +``` + +### Spying example + +Button counter component is used in several Vue doc examples + +```vue + + + + + +``` + +Let us test it - how do we ensure the event is emitted when the button is clicked? +Simple - let us spy on the event, [spying and stubbing is built into Cypress](https://on.cypress.io/stubs-spies-and-clocks) + +```js +import ButtonCounter from '../../components/ButtonCounter.vue' +import { mountCallback } from '@cypress/vue2' + +describe('ButtonCounter', () => { + beforeEach(mountCallback(ButtonCounter)) + + it('starts with zero', () => { + cy.contains('button', '0') + }) + + it('increments the counter on click', () => { + cy.get('button').click().click().click().contains('3') + }) + + it('emits "increment" event on click', () => { + const spy = cy.spy() + Cypress.vue.$on('increment', spy) + cy.get('button') + .click() + .click() + .then(() => { + expect(spy).to.be.calledTwice + }) + }) +}) +``` + +The component is really updating the counter in response to the click +and is emitting an event. + +![Spying test](images/spy-spec.png) + +[cypress.io]: https://www.cypress.io/ + +
+ +### XHR spying and stubbing + +The mount function automatically wraps XMLHttpRequest giving you an ability to intercept XHR requests your component might do. For full documentation see [Network Requests](https://on.cypress.io/network-requests). In this repo see [components/AjaxList.vue](components/AjaxList.vue) and the corresponding tests [cypress/integration/ajax-list-spec.js](cypress/integration/ajax-list-spec.js). + +```js +// component use axios to get list of users +created() { + axios.get(`https://jsonplaceholder.cypress.io/users?_limit=3`) + .then(response => { + // JSON responses are automatically parsed. + this.users = response.data + }) +} +// test can observe, return mock data, delay and a lot more +beforeEach(mountCallback(AjaxList)) +it('can inspect real data in XHR', () => { + cy.server() + cy.route('/users?_limit=3').as('users') + cy.wait('@users').its('response.body').should('have.length', 3) +}) +it('can display mock XHR response', () => { + cy.server() + const users = [{id: 1, name: 'foo'}] + cy.route('GET', '/users?_limit=3', users).as('users') + cy.get('li').should('have.length', 1) + .first().contains('foo') +}) +``` + + + +### Spying on `window.alert` + +Calls to `window.alert` are automatically recorded, but do not show up. Instead you can spy on them, see [AlertMessage.vue](components/AlertMessage.vue) and its test [cypress/integration/alert-spec.js](cypress/integration/alert-spec.js) + +## Comparison + + +Feature | Vue Test Utils or @testing-library/vue | Cypress + `@cypress/vue2` +--- | --- | --- +Test runs in real browser | โŒ | โœ… +Uses full mount | โŒ | โœ… +Test speed | ๐ŸŽ | as fast as the app works in the browser +Test can use additional plugins | maybe | use any [Cypress plugin](https://on.cypress.io/plugins) +Test can interact with component | synthetic limited API | use any [Cypress command](https://on.cypress.io/api) +Test can be debugged | via terminal and Node debugger | use browser DevTools +Built-in time traveling debugger | โŒ | Cypress time traveling debugger +Re-run tests on file or test change | โœ… | โœ… +Test output on CI | terminal | terminal, screenshots, videos +Tests can be run in parallel | โœ… | โœ… via [parallelization](https://on.cypress.io/parallelization) +Test against interface | if using `@testing-library/vue` | โœ… and can use `@testing-library/cypress` +Spying and mocking | Jest mocks | Sinon library +Code coverage | โœ… | โœ… + + +## Examples + +```js +// components/HelloWorld.spec.js +import { mount } from '@cypress/vue2' +import { HelloWorld } from './HelloWorld.vue' +describe('HelloWorld component', () => { + it('works', () => { + mount(HelloWorld) + // now use standard Cypress commands + cy.contains('Hello World!').should('be.visible') + }) +}) +``` + +### Basic examples + + +Spec | Description +--- | --- +[Components](cypress/component/basic/components) | Registers global components to use +[Filters](cypress/component/basic/filters) | Registering global filters +[Hello](cypress/component/basic/hello) | Testing examples from Vue2 cookbook +[Mixins](cypress/component/basic/mixins) | Registering Vue mixins +[Plugins](cypress/component/basic/plugins) | Loading additional plugins +[Props](cypress/component/basic/props) | Pass props to the component during mount +[Slots](cypress/component/basic/slots) | Passing slots and scopedSlots to the component +[Small examples](cypress/component/basic/small-examples) | A few small examples testing forms, buttons + + +### Advanced examples + + +Spec | Description +--- | --- +[access-component](cypress/component/advanced/access-component) | Access the mounted component directly from test +[i18n](cypress/component/advanced/i18n) | Testing component that uses [Vue I18n](https://kazupon.github.io/vue-i18n/) plugin +[mocking-axios](cypress/component/advanced/mocking-axios) | Mocking 3rd party CommonJS modules like `axios` +[mocking-fetch](cypress/component/advanced/mocking-fetch) | Mocking `window.fetch` to stub responses and test the UI +[fetch-polyfill](ypress/component/advanced/fetch-polyfill) | Using experimental `fetch` polyfill to spy on / stub those Ajax requests using regular Cypress network methods +[mocking-components](cypress/component/advanced/mocking-components) | Mocking locally registered child components during tests +[mocking-imports](cypress/component/advanced/mocking-imports) | Stub ES6 imports from the tests +[render-functions](cypress/component/advanced/render-functions) | Mounting components with a [render function](https://www.tutorialandexample.com/vue-js-render-functions/) + + +### Full examples + +We have several subfolders in [examples](examples) folder. + + +Folder Name | Description +--- | --- +[cli](examples/cli) | An example app scaffolded using Vue CLI and the component testing added using `vue add cypress-experimental` command. + + +### External examples + + +Repo | Description +--- | --- +[vue-component-test-example](https://github.com/bahmutov/vue-component-test-example) | Scaffolded Vue CLI v3 project with added component tests, read [Write Your First Vue Component Test](https://glebbahmutov.com/blog/first-vue-component-test/). + + + + +## Code coverage + +This plugin uses `babel-plugin-istanbul` to automatically instrument `.js` and `.vue` files and generates the code coverage report using dependency [cypress-io/code-coverage](https://github.com/cypress-io/code-coverage) (included). The output reports are saved in the folder "coverage" at the end of the test run. + +If you want to disable code coverage instrumentation and reporting, use `--env coverage=false` or `CYPRESS_coverage=false` or set in your `cypress.json` file + +```json +{ + "env": { + "coverage": false + } +} +``` + +**Note โš ๏ธ:** if the component `.vue` file does not have a ` + + + + + \ No newline at end of file diff --git a/packages/app/package.json b/packages/app/package.json new file mode 100644 index 0000000000..c7b670a16b --- /dev/null +++ b/packages/app/package.json @@ -0,0 +1,115 @@ +{ + "name": "@packages/app", + "version": "0.0.0-development", + "private": true, + "scripts": { + "check-ts": "vue-tsc --noEmit", + "build-prod-ui": "cross-env NODE_ENV=production vite build", + "clean": "rimraf dist && rimraf ./node_modules/.vite && echo 'cleaned'", + "clean-deps": "rimraf node_modules", + "test": "echo 'ok'", + "cypress:run-cypress-in-cypress": "cross-env HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS=http://localhost:4455 CYPRESS_REMOTE_DEBUGGING_PORT=6666 TZ=America/New_York", + "cypress:launch": "yarn cypress:run-cypress-in-cypress gulp open --project .", + "cypress:open": "yarn cypress:run-cypress-in-cypress gulp open --project .", + "cypress:run:ct": "yarn cypress:run-cypress-in-cypress node ../../scripts/cypress run --component --project .", + "cypress:run:e2e": "yarn cypress:run-cypress-in-cypress node ../../scripts/cypress run --project .", + "dev": "yarn cypress:run-cypress-in-cypress gulp dev --project .", + "start": "echo \"run 'yarn dev' from the root\" && exit 1", + "watch": "echo \"run 'yarn dev' from the root\" && exit 1" + }, + "dependencies": {}, + "devDependencies": { + "@cypress/vue": "0.0.0-development", + "@graphql-typed-document-node/core": "^3.1.0", + "@headlessui/vue": "1.4.0", + "@iconify/iconify": "2.1.2", + "@iconify/json": "1.1.368", + "@iconify/vue": "3.0.0-beta.1", + "@intlify/vite-plugin-vue-i18n": "2.4.0", + "@packages/frontend-shared": "0.0.0-development", + "@percy/cypress": "^3.1.0", + "@testing-library/cypress": "8.0.0", + "@types/faker": "5.5.8", + "@urql/core": "2.3.1", + "@urql/vue": "0.4.3", + "@vitejs/plugin-vue": "2.2.4", + "@vitejs/plugin-vue-jsx": "1.3.8", + "@vueuse/core": "7.2.2", + "@windicss/plugin-interaction-variants": "1.0.0", + "ansi-to-html": "0.6.14", + "bluebird": "3.5.3", + "classnames": "2.3.1", + "combine-properties": "0.1.0", + "concurrently": "^6.2.0", + "cross-env": "6.0.3", + "cypress-real-events": "1.6.0", + "disparity": "^3.0.0", + "faker": "5.5.3", + "fuzzysort": "^1.1.4", + "graphql": "^15.5.1", + "graphql-tag": "^2.12.5", + "human-interval": "1.0.0", + "javascript-time-ago": "2.3.8", + "just-my-luck": "3.0.0", + "lodash": "4.17.21", + "mobx": "5.15.4", + "pinia": "2.0.0-rc.14", + "rimraf": "3.0.2", + "rollup-plugin-copy": "3.4.0", + "rollup-plugin-polyfill-node": "^0.7.0", + "unplugin-icons": "0.13.2", + "unplugin-vue-components": "^0.15.2", + "vite": "2.9.0-beta.3", + "vite-plugin-components": "0.11.3", + "vite-plugin-pages": "0.18.1", + "vite-plugin-vue-layouts": "0.4.1", + "vite-plugin-windicss": "1.2.4", + "vite-svg-loader": "3.1.2", + "vue": "3.2.31", + "vue-i18n": "9.2.0-beta.7", + "vue-router": "4", + "vue-tsc": "^0.3.0", + "windicss": "3.1.4", + "wonka": "^4.0.15" + }, + "files": [ + "dist", + "lib", + "src" + ], + "vite": { + "optimizeDeps": { + "include": [ + "@headlessui/vue", + "@iconify/iconify", + "@percy/cypress", + "@testing-library/cypress/add-commands", + "@urql/exchange-execute", + "@urql/vue", + "@vueuse/core", + "bluebird", + "cypress-real-events", + "dedent", + "events", + "fake-uuid", + "fuzzysort", + "graphql", + "graphql-relay", + "graphql/jsutils/Path", + "gravatar", + "human-interval", + "lodash", + "mobx", + "nanoid", + "path", + "pinia", + "shiki", + "socket.io-client", + "vue", + "vue-demi", + "vue-toastification", + "wonka" + ] + } + } +} diff --git a/packages/app/src/App.vue b/packages/app/src/App.vue new file mode 100644 index 0000000000..dc01bce359 --- /dev/null +++ b/packages/app/src/App.vue @@ -0,0 +1,7 @@ + diff --git a/packages/app/src/components/Blank.cy.tsx b/packages/app/src/components/Blank.cy.tsx new file mode 100644 index 0000000000..e99ff73db7 --- /dev/null +++ b/packages/app/src/components/Blank.cy.tsx @@ -0,0 +1,69 @@ +import { initial, initialCT, session, sessionLifecycle, visitFailure } from './Blank' +import { getContainerEl } from '@cypress/mount-utils' + +describe('initial - e2e', () => { + beforeEach(() => { + getContainerEl()!.innerHTML = initial() + }) + + it('works', () => { + cy.percySnapshot() + }) + + it('links to docs', () => { + cy.contains('cy.visit').should('have.attr', 'href', 'https://on.cypress.io/visit') + }) +}) + +describe('initial - ct', () => { + it('works', () => { + getContainerEl()!.innerHTML = initialCT() + + cy.percySnapshot() + }) + + it('links to docs', () => { + getContainerEl()!.innerHTML = initialCT() + + cy.contains('mount').should('have.attr', 'href', 'https://on.cypress.io/mount') + }) + + it('works with small viewport', () => { + cy.viewport(200, 1000) + getContainerEl()!.innerHTML = initial() + + cy.percySnapshot() + }) +}) + +describe('session', () => { + it('works', () => { + getContainerEl()!.innerHTML = session() + + cy.percySnapshot() + }) +}) + +describe('sessionLifecycle', () => { + it('works', () => { + getContainerEl()!.innerHTML = sessionLifecycle() + + cy.get('.warn').contains('experimentalSessionSupport') + + cy.percySnapshot() + }) +}) + +describe('visitFailure', () => { + it('works', () => { + getContainerEl()!.innerHTML = visitFailure({ url: 'http://foo.cypress.io' }) + + cy.percySnapshot() + }) + + it('works with details', () => { + getContainerEl()!.innerHTML = visitFailure({ url: 'http://foo.cypress.io', status: 404, statusText: 'Not Found', contentType: 'text/html' }) + + cy.percySnapshot() + }) +}) diff --git a/packages/app/src/components/Blank.jsx b/packages/app/src/components/Blank.jsx new file mode 100644 index 0000000000..9194efd8de --- /dev/null +++ b/packages/app/src/components/Blank.jsx @@ -0,0 +1,284 @@ +const svgCy = ` + + + +` + +const svgWarning = `` + +const defaultStyles = ` + body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img,a img{border:none;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;} + + * { + box-sizing: border-box; + } + + body { + color: #1b1e2e; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 1.4; + padding: 20px; + width: 100%; + height: 100%; + } + + pre { + text-align: left; + display: flex; + } + + code { + font-family: 'Fira Code', monospace; + } + + pre code { + margin: 0 auto; + } + + .container { + background-color: #f3f4fa; + border-radius: 8px; + border: 2px dashed #e1e3ed; + padding: 32px 16px; + text-align: center; + height: 100%; + } + + svg { + display: inline-block; + stroke-width: 0; + stroke: currentColor; + fill: currentColor; + margin: 16px 0; + width: 64px; + } + + p { + font-size: 21px; + font-weight: 200; + line-height: 1.4; + } + + kbd { + background-color: #747994; + border-radius: 3px; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #fff; + display: inline-block; + font-size: 85%; + padding: 2px 4px; + } + + a, + a:hover, + a:focus, + a:active { + color: currentColor; + text-decoration: underline; + } +` + +const listStyles = ` +ul { + text-align: left; + margin: 0 auto 10px; + display: inline-block; + padding: 20px 20px 20px 40px; +} + +li { + list-style: decimal; + list-style-position: outside; + margin: 4px 0; +} +` + +export const initial = () => { + return ` + + + + ` +} + +export const initialCT = () => { + return ` + + +
+ ${svgCy} +

This is the default blank page.

+

To test your web application:

+
    +
  • Mount your component with + + mount() + +
  • +
  • Begin writing tests
  • +
+
+ ` +} + +export const sessionLifecycle = () => { + return ` + + +
+ ${svgCy} +
+

Because experimentalSessionSupport is enabled, Cypress navigates to the default blank page before each test to ensure test reliability.

+

This is the default blank page.

+

To test your web application:

+
    +
  • Start your app's server
  • +
  • + + cy.visit() + + your app +
  • +
  • Begin writing tests
  • +
+
+ ` +} + +export const session = () => { + return ` + + +
+ ${svgCy} +

This is a blank page.

+

We always navigate you here after cy.session()

+

To continue your test, follow up the command with + cy.visit() +

+

+1 |
+2 | cy.session(...)
+3 | cy.visit(...)
+4 |
+
+ +
+ ` +} + +export const visitFailure = (props) => { + const { status, statusText, contentType } = props + + const getContentType = () => { + if (!contentType) { + return '' + } + + return `(${contentType})` + } + + const getStatus = () => { + if (!status) { + return '' + } + + return `

${status} - ${statusText} ${getContentType()}

` + } + + return ` + + +
+ ${svgWarning} +

Sorry, we could not load:

+

+ ${props.url} +

+ ${getStatus()} + +
+ ` +} + +export const blankContents = { + initial, + initialCT, + session, + sessionLifecycle, + visitFailure, +} diff --git a/packages/app/src/components/FileMatch.cy.tsx b/packages/app/src/components/FileMatch.cy.tsx new file mode 100644 index 0000000000..8ec23e763b --- /dev/null +++ b/packages/app/src/components/FileMatch.cy.tsx @@ -0,0 +1,193 @@ +import FileMatch from './FileMatch.vue' +import { ref } from 'vue' +import { defaultMessages } from '@cy/i18n' +import { each } from 'lodash' + +/*---------- Selectors ----------*/ +// Inputs +const anyFilenameInputSelector = `[placeholder="${defaultMessages.components.fileSearch.byFilenameInput}"]` +const filenameInputSelector = `${anyFilenameInputSelector}:first` +const extensionInputSelector = `[placeholder="${defaultMessages.components.fileSearch.byExtensionInput}"]` +const fileMatchButtonSelector = '[data-cy=file-match-button]' + +// File Match Indicator +// X out of Y Matches when searching the file list +const fileMatchIndicatorSelector = '[data-cy=file-match-indicator]' + +const initialExtension = '*.stories.*' +const initialPattern = '' + +describe('', { viewportWidth: 600, viewportHeight: 300 }, () => { + describe('with some matches', () => { + beforeEach(() => { + const extensionPattern = ref(initialExtension) + const pattern = ref(initialPattern) + const matches = { total: 10, found: 9 } + + const onUpdateExtensionPatternSpy = cy.spy().as('onUpdateExtensionPatternSpy') + const onUpdatePatternSpy = cy.spy().as('onUpdatePatternSpy') + + const methods = { + 'onUpdate:extensionPattern': (newValue) => { + extensionPattern.value = newValue + onUpdateExtensionPatternSpy(newValue) + }, + 'onUpdate:pattern': (newValue) => { + pattern.value = newValue + onUpdatePatternSpy(newValue) + }, + } + + cy.mount(() => (
+ +
)) + }) + + describe('expanding/collapsing', () => { + it('can be expanded and collapsed by the extension button', () => { + cy.get(extensionInputSelector).should('not.exist') + cy.percySnapshot('before expand') + cy.get(fileMatchButtonSelector).click() + .get(extensionInputSelector).should('be.visible') + + cy.percySnapshot('after expand') + cy.get(fileMatchButtonSelector).click() + .get(extensionInputSelector).should('not.exist') + }) + + it('shows the extension textfield when expanded', () => { + cy.get(extensionInputSelector).should('not.exist') + .get(fileMatchButtonSelector).click() + .get(extensionInputSelector) + .should('be.visible').and('have.value', initialExtension) + }) + + it('shows the file name textfield when collapsed', () => { + cy.get(filenameInputSelector).should('be.visible') + }) + + it('shows the file name textfield when expanded', () => { + cy.get(fileMatchButtonSelector).click() + .get(filenameInputSelector).should('be.visible') + }) + + it('persists the file name search between collapsing and expanding', () => { + const newText = 'New filename' + + cy.get(filenameInputSelector).should('be.visible') + .clear() + .type(newText) + .get(fileMatchButtonSelector).click() + .get(anyFilenameInputSelector).should('have.length', 1) + .get(filenameInputSelector).should('have.value', newText) + .get(fileMatchButtonSelector).click() + .get(filenameInputSelector).should('have.value', newText) + }) + + it('persists the extension search between collapsing and expanding', () => { + const newText = 'New extension' + + cy.get(extensionInputSelector).should('not.exist') + .get(fileMatchButtonSelector).click() + .get(extensionInputSelector).should('be.visible') + .clear() + .type(newText) + .get(fileMatchButtonSelector).click().click() + .get(extensionInputSelector).should('be.visible').and('have.value', newText) + }) + + it('displays the extension in the extension button when collapsed', () => { + const newText = 'New extension' + + cy.get(extensionInputSelector).should('not.exist') + .get(fileMatchButtonSelector).click() + .get(extensionInputSelector).should('be.visible') + .clear() + .type(newText) + .get(fileMatchButtonSelector).click() + .should('contain.text', newText) + }) + + it('does not display in the extension button when expanded', () => { + cy.get(extensionInputSelector).should('not.exist') + .get(fileMatchButtonSelector).click() + .should('have.text', '') + .click() + .should('have.text', initialExtension) + }) + }) + + describe('extensionPattern', () => { + it('emits the update:extensionPattern event', () => { + const newExtension = '*.tsx' + + cy.get(fileMatchButtonSelector).click() + .get(extensionInputSelector) + .clear() + .type(newExtension) + .get('@onUpdateExtensionPatternSpy') + .should('have.been.calledWith', newExtension) + }) + + it('displays the initial extension pattern', () => { + cy.get(fileMatchButtonSelector).should('have.text', initialExtension) + .click() + .get(extensionInputSelector).should('have.value', initialExtension) + }) + }) + + describe('pattern', () => { + it('emits the update:pattern event', () => { + const newFilePattern = 'BaseComponent' + + cy.get(filenameInputSelector).type(newFilePattern) + .get('@onUpdatePatternSpy') + .should('have.been.calledWith', newFilePattern) + }) + }) + }) + + describe('indicator', () => { + /*---------- Fixtures ----------*/ + // Matches + const total = 10 + const matchesData: Record = { + all: [ + { matches: { found: 10, total } }, + '10 Matches', + ], + 'ignores numerator when file pattern isn\'t searched': [ + { matches: { found: 9, total } }, + '10 Matches', + ], + 'shows numerator when file pattern is searched': [ + { matches: { found: 9, total }, pattern: 'A Pattern', extensionPattern: '*.tsx' }, + '9 of 10 Matches', + ], + one: [ + { matches: { found: 1, total }, pattern: 'A Pattern', extensionPattern: '*.tsx' }, + '1 of 10 Matches', + ], + 'one without a pattern': [ + { matches: { found: 1, total } }, + '1 Match', + ], + 'no matches': [ + { matches: { found: 0, total: 0 } }, + 'No Matches', + ], + } + + each(matchesData, ([theProps, expected], key) => { + it(`displays ${key} matches`, () => { + cy.mount(() => ) + .get(fileMatchIndicatorSelector) + .should('have.text', expected) + }) + }) + }) +}) diff --git a/packages/app/src/components/FileMatch.vue b/packages/app/src/components/FileMatch.vue new file mode 100644 index 0000000000..f5675fd4f6 --- /dev/null +++ b/packages/app/src/components/FileMatch.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/packages/app/src/components/FileMatchButton.cy.tsx b/packages/app/src/components/FileMatchButton.cy.tsx new file mode 100644 index 0000000000..df8cfa64e2 --- /dev/null +++ b/packages/app/src/components/FileMatchButton.cy.tsx @@ -0,0 +1,44 @@ +// Anything with onClick SHOULD work, but isn't... +// Defining emits for "Button.vue" removes the native handler on the +// ') + expect(err.message).to.include('> `cy.click()`') + expect(err.docsUrl).to.eq('https://on.cypress.io/element-has-detached-from-dom') + + done() + }) + + cy.get('#button').click().parent() + }) + + it('fails when previous subject isnt window', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('`cy.winOnly()` failed because it requires the subject be a global `window` object.') + expect(err.message).to.include('{foo: bar}') + expect(err.message).to.include('> `cy.wrap()`') + + done() + }) + + cy.wrap({ foo: 'bar' }).winOnly() + }) + + it('fails when previous subject isnt document', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('`cy.docOnly()` failed because it requires the subject be a global `document` object.') + expect(err.message).to.include('[1, 2, 3]') + expect(err.message).to.include('> `cy.wrap()`') + + done() + }) + + cy.wrap([1, 2, 3]).docOnly() + }) + + it('fails when previous subject isnt an element or window', (done) => { + let firstPassed = false + + cy.on('fail', (err) => { + expect(firstPassed).to.be.true + expect(err.message).to.include('`cy.elWinOnly()` failed because it requires a DOM element.') + expect(err.message).to.include('string') + expect(err.message).to.include('> `cy.wrap()`') + expect(err.message).to.include('All 2 subject validations failed') + + done() + }) + + cy.window().elWinOnly() + .then(() => { + firstPassed = true + + cy.wrap('string').elWinOnly() + }) + }) + }) + + describe('dual commands', () => { + beforeEach(() => { + Cypress.Commands.add('d', { prevSubject: 'optional' }, (subject, arg) => { + cy.wrap([subject, arg]) + }) + }) + + it('passes on subject when used as a child', () => { + cy + .wrap('foo') + .d('bar') + .then((arr) => { + expect(arr).to.deep.eq(['foo', 'bar']) + }) + }) + + it('has an undefined subject when used as a parent', () => { + cy + .d('bar') + .then((arr) => { + expect(arr).to.deep.eq([undefined, 'bar']) + }) + }) + + it('has an undefined subject as a parent with a previous parent', () => { + cy.wrap('foo') + + cy + .d('bar') + .then((arr) => { + expect(arr).to.deep.eq([undefined, 'bar']) + }) + .wrap('foo') + .d('bar') + .then((arr) => { + expect(arr).to.deep.eq(['foo', 'bar']) + + return null + }) + .d('baz') + .then((arr) => { + expect(arr).to.deep.eq([null, 'baz']) + }) + }) + }) + }) + + context('overwrite custom commands', () => { + beforeEach(() => { + Cypress.Commands.overwrite('wrap', (orig, arg1) => { + return orig(`foo${arg1}`) + }) + + Cypress.Commands.overwrite('first', (orig, subject) => { + subject = $([1, 2]) + + return orig(subject) + }) + + Cypress.Commands.overwrite('noop', function (orig, fn) { + // yield the context + return fn(this) + }) + + Cypress.Commands.overwrite('submit', (orig, subject) => { + return orig(subject, { foo: 'foo' }) + }) + }) + + it('can modify parent commands', () => { + cy.wrap('bar').then((str) => { + expect(str).to.eq('foobar') + }) + }) + + it('can modify child commands', () => { + cy.get('li').first().then((el) => { + expect(el[0]).to.eq(1) + }) + }) + + it('has the current runnable ctx', function () { + const _this = this + + cy.noop((ctx) => { + expect(_this === ctx).to.be.true + }) + }) + + it('overwrites only once', () => { + Cypress.Commands.overwrite('wrap', (orig, arg1) => { + return orig(`${arg1}baz`) + }) + + cy.wrap('bar').should('eq', 'barbaz') + }) + + it('errors when command does not exist', () => { + const fn = () => { + Cypress.Commands.overwrite('foo', () => {}) + } + + expect(fn).to.throw().with.property('message') + .and.include('Cannot overwite command for: `foo`. An existing command does not exist by that name.') + + expect(fn).to.throw().with.property('docsUrl') + .and.include('https://on.cypress.io/api') + }) + + it('updates state(\'current\') with modified args', () => { + cy.get('form').eq(0).submit().then(() => { + expect(cy.state('current').get('prev').get('args')[0].foo).to.equal('foo') + }) + }) + + // https://github.com/cypress-io/cypress/issues/18892 + it('passes this through to overwritten command', () => { + Cypress.Commands.add('bar', function () { + expect(this.test.title).to.exist + }) + + cy.bar() + + Cypress.Commands.overwrite('bar', function (originalFn) { + return originalFn.call(this) + }) + + cy.bar() + }) + }) +}) diff --git a/packages/driver/cypress/integration/cypress/cypress_spec.js b/packages/driver/cypress/e2e/cypress/cypress.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/cypress_spec.js rename to packages/driver/cypress/e2e/cypress/cypress.cy.js diff --git a/packages/driver/cypress/integration/cypress/downloads_spec.ts b/packages/driver/cypress/e2e/cypress/downloads.cy.ts similarity index 100% rename from packages/driver/cypress/integration/cypress/downloads_spec.ts rename to packages/driver/cypress/e2e/cypress/downloads.cy.ts diff --git a/packages/driver/cypress/integration/cypress/error_utils_spec.ts b/packages/driver/cypress/e2e/cypress/error_utils.cy.ts similarity index 100% rename from packages/driver/cypress/integration/cypress/error_utils_spec.ts rename to packages/driver/cypress/e2e/cypress/error_utils.cy.ts diff --git a/packages/driver/cypress/integration/cypress/keyboard_spec.js b/packages/driver/cypress/e2e/cypress/keyboard.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/keyboard_spec.js rename to packages/driver/cypress/e2e/cypress/keyboard.cy.js diff --git a/packages/driver/cypress/integration/cypress/location_spec.js b/packages/driver/cypress/e2e/cypress/location.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/location_spec.js rename to packages/driver/cypress/e2e/cypress/location.cy.js diff --git a/packages/driver/cypress/integration/cypress/log_spec.js b/packages/driver/cypress/e2e/cypress/log.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/log_spec.js rename to packages/driver/cypress/e2e/cypress/log.cy.js diff --git a/packages/driver/cypress/integration/cypress/network_utils_spec.js b/packages/driver/cypress/e2e/cypress/network_utils.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/network_utils_spec.js rename to packages/driver/cypress/e2e/cypress/network_utils.cy.js diff --git a/packages/driver/cypress/integration/cypress/proxy-logging_spec.ts b/packages/driver/cypress/e2e/cypress/proxy-logging.cy.ts similarity index 100% rename from packages/driver/cypress/integration/cypress/proxy-logging_spec.ts rename to packages/driver/cypress/e2e/cypress/proxy-logging.cy.ts diff --git a/packages/driver/cypress/integration/cypress/resolvers_spec.ts b/packages/driver/cypress/e2e/cypress/resolvers.cy.ts similarity index 100% rename from packages/driver/cypress/integration/cypress/resolvers_spec.ts rename to packages/driver/cypress/e2e/cypress/resolvers.cy.ts diff --git a/packages/driver/cypress/integration/cypress/runner_spec.js b/packages/driver/cypress/e2e/cypress/runner.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/runner_spec.js rename to packages/driver/cypress/e2e/cypress/runner.cy.js diff --git a/packages/driver/cypress/integration/cypress/screenshot_spec.js b/packages/driver/cypress/e2e/cypress/screenshot.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/screenshot_spec.js rename to packages/driver/cypress/e2e/cypress/screenshot.cy.js diff --git a/packages/driver/cypress/integration/cypress/script_utils_spec.js b/packages/driver/cypress/e2e/cypress/script_utils.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/script_utils_spec.js rename to packages/driver/cypress/e2e/cypress/script_utils.cy.js diff --git a/packages/driver/cypress/integration/cypress/selector_playground_spec.js b/packages/driver/cypress/e2e/cypress/selector_playground.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/selector_playground_spec.js rename to packages/driver/cypress/e2e/cypress/selector_playground.cy.js diff --git a/packages/driver/cypress/integration/cypress/shadow_dom_utils_spec.ts b/packages/driver/cypress/e2e/cypress/shadow_dom_utils.cy.ts similarity index 100% rename from packages/driver/cypress/integration/cypress/shadow_dom_utils_spec.ts rename to packages/driver/cypress/e2e/cypress/shadow_dom_utils.cy.ts diff --git a/packages/driver/cypress/integration/cypress/source_map_utils_spec.js b/packages/driver/cypress/e2e/cypress/source_map_utils.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/source_map_utils_spec.js rename to packages/driver/cypress/e2e/cypress/source_map_utils.cy.js diff --git a/packages/driver/cypress/e2e/cypress/stack_utils.cy.js b/packages/driver/cypress/e2e/cypress/stack_utils.cy.js new file mode 100644 index 0000000000..e5416a5ca7 --- /dev/null +++ b/packages/driver/cypress/e2e/cypress/stack_utils.cy.js @@ -0,0 +1,537 @@ +const $stackUtils = require('@packages/driver/src/cypress/stack_utils').default +const $sourceMapUtils = require('@packages/driver/src/cypress/source_map_utils').default +const { stripIndent } = require('common-tags') + +describe('driver/src/cypress/stack_utils', () => { + context('.replacedStack', () => { + const message = 'Original error\n\nline 2' + + it('returns stack with original message', () => { + const err = new Error(message) + const newStack = 'at foo (path/to/file.js:1:1)\nat bar (path/to/file.js:2:2)' + const stack = $stackUtils.replacedStack(err, newStack) + + expect(stack).to.equal(`Error: ${message}\n${newStack}`) + }) + + it('does not replace stack if error has no stack', () => { + const err = new Error(message) + + err.stack = '' + const stack = $stackUtils.replacedStack(err, 'new stack') + + expect(stack).to.equal('') + }) + }) + + context('.getCodeFrame', () => { + let originalErr + const sourceCode = `it('is a failing test', () => { + cy.get('.not-there') +})\ +` + + beforeEach(() => { + originalErr = { + parsedStack: [ + { message: 'Only a message' }, + { + fileUrl: 'http://localhost:12345/__cypress/tests?p=cypress/integration/features/source_map_spec.js', + absoluteFile: '/dev/app/cypress/integration/features/source_map_spec.js', + relativeFile: 'cypress/integration/features/source_map_spec.js', + line: 2, + column: 5, + }, + ], + } + }) + + it('returns existing code frame if error already has one', () => { + const existingCodeFrame = {} + + originalErr.codeFrame = existingCodeFrame + + expect($stackUtils.getCodeFrame(originalErr)).to.equal(existingCodeFrame) + }) + + it('returns undefined if there is no parsed stack', () => { + originalErr.parsedStack = undefined + + expect($stackUtils.getCodeFrame(originalErr)).to.be.undefined + }) + + it('returns undefined if parsed stack is empty', () => { + originalErr.parsedStack = [] + + expect($stackUtils.getCodeFrame(originalErr)).to.be.undefined + }) + + it('returns undefined if there are only message lines', () => { + originalErr.parsedStack = [{ message: 'Only a message' }] + + expect($stackUtils.getCodeFrame(originalErr)).to.be.undefined + }) + + it('returns code frame from first stack line', () => { + cy.stub($sourceMapUtils, 'getSourceContents').returns(sourceCode) + + const codeFrame = $stackUtils.getCodeFrame(originalErr) + + expect(codeFrame).to.be.an('object') + expect(codeFrame.frame).to.contain(` 1 | it('is a failing test', () => {`) + expect(codeFrame.frame).to.contain(`> 2 | cy.get('.not-there'`) + expect(codeFrame.frame).to.contain(` | ^`) + expect(codeFrame.frame).to.contain(` 3 | }`) + expect(codeFrame.absoluteFile).to.equal('/dev/app/cypress/integration/features/source_map_spec.js') + expect(codeFrame.relativeFile).to.equal('cypress/integration/features/source_map_spec.js') + expect(codeFrame.language).to.equal('js') + expect(codeFrame.line).to.equal(2) + expect(codeFrame.column).to.eq(5) + }) + + it('does not add code frame if stack does not yield one', () => { + cy.stub($sourceMapUtils, 'getSourceContents').returns(null) + + expect($stackUtils.getCodeFrame(originalErr)).to.be.undefined + }) + }) + + context('.getSourceStack when http links', () => { + it('does not have absolute files', () => { + const projectRoot = '/dev/app' + + cy.fixture('error-stack-with-http-links.txt') + .then((stack) => { + return $stackUtils.getSourceStack(stack, projectRoot) + }) + .its('parsed') + .then((parsed) => { + return Cypress._.find(parsed, { fileUrl: 'http://localhost:8888/js/utils.js' }) + }) + .then((errorLocation) => { + expect(errorLocation, 'does not have disk information').to.deep.equal({ + absoluteFile: undefined, + column: 4, + fileUrl: 'http://localhost:8888/js/utils.js', + function: '', + line: 9, + originalFile: 'http://localhost:8888/js/utils.js', + relativeFile: undefined, + whitespace: ' ', + }) + }) + }) + }) + + context('.getSourceStack', () => { + let generatedStack + const projectRoot = '/dev/app' + + beforeEach(() => { + cy.stub($sourceMapUtils, 'getSourcePosition').returns({ + file: 'some_other_file.ts', + line: 2, + column: 1, + }) + + $sourceMapUtils.getSourcePosition.onCall(1).returns({ + file: 'cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 3, + }) + + generatedStack = `Error: spec iframe stack + at foo.bar (http://localhost:1234/source_map_spec.js:12:4) + at Context. (http://localhost:1234/tests?p=cypress/integration/features/source_map_spec.js:6:4)\ +` + }) + + it('receives generated stack and returns object with source stack and parsed source stack', () => { + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(`Error: spec iframe stack + at foo.bar (some_other_file.ts:2:2) + at Context. (cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + + expect(sourceStack.parsed).to.eql([ + { + message: 'Error: spec iframe stack', + whitespace: '', + }, + { + function: 'foo.bar', + fileUrl: 'http://localhost:1234/source_map_spec.js', + originalFile: 'some_other_file.ts', + relativeFile: 'some_other_file.ts', + absoluteFile: '/dev/app/some_other_file.ts', + line: 2, + column: 2, + whitespace: ' ', + }, + { + function: 'Context.', + fileUrl: 'http://localhost:1234/tests?p=cypress/integration/features/source_map_spec.js', + originalFile: 'cypress/integration/features/source_map_spec.coffee', + relativeFile: 'cypress/integration/features/source_map_spec.coffee', + absoluteFile: '/dev/app/cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 4, + whitespace: ' ', + }, + ]) + }) + + it('works when first line is the error message', () => { + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(`Error: spec iframe stack + at foo.bar (some_other_file.ts:2:2) + at Context. (cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + }) + + it('works when first line is not the error message', () => { + generatedStack = generatedStack.split('\n').slice(1).join('\n') + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(` at foo.bar (some_other_file.ts:2:2) + at Context. (cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + }) + + it('works when first several lines are the error message', () => { + generatedStack = `Some\nmore\nlines\n\n${generatedStack}` + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(`Some +more +lines + +Error: spec iframe stack + at foo.bar (some_other_file.ts:2:2) + at Context. (cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + }) + + it('strips webpack protocol from relativeFile and maintains it in originalFile', () => { + $sourceMapUtils.getSourcePosition.returns({ + file: 'cypress:///some_other_file.ts', + line: 2, + column: 1, + }) + + $sourceMapUtils.getSourcePosition.onCall(1).returns({ + file: 'webpack:///cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 3, + }) + + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(`Error: spec iframe stack + at foo.bar (cypress:///some_other_file.ts:2:2) + at Context. (webpack:///cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + + expect(sourceStack.parsed).to.eql([ + { + message: 'Error: spec iframe stack', + whitespace: '', + }, + { + function: 'foo.bar', + fileUrl: 'http://localhost:1234/source_map_spec.js', + originalFile: 'cypress:///some_other_file.ts', + relativeFile: 'some_other_file.ts', + absoluteFile: '/dev/app/some_other_file.ts', + line: 2, + column: 2, + whitespace: ' ', + }, + { + function: 'Context.', + fileUrl: 'http://localhost:1234/tests?p=cypress/integration/features/source_map_spec.js', + originalFile: 'webpack:///cypress/integration/features/source_map_spec.coffee', + relativeFile: 'cypress/integration/features/source_map_spec.coffee', + absoluteFile: '/dev/app/cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 4, + whitespace: ' ', + }, + ]) + }) + + it('strips webpack protocol and maintains absolute path', () => { + $sourceMapUtils.getSourcePosition.returns({ + file: 'cypress:////root/absolute/path/some_other_file.ts', + line: 2, + column: 1, + }) + + $sourceMapUtils.getSourcePosition.onCall(1).returns({ + file: 'webpack:////root/absolute/path/cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 3, + }) + + const sourceStack = $stackUtils.getSourceStack(generatedStack, projectRoot) + + expect(sourceStack.sourceMapped).to.equal(`Error: spec iframe stack + at foo.bar (cypress:////root/absolute/path/some_other_file.ts:2:2) + at Context. (webpack:////root/absolute/path/cypress/integration/features/source_map_spec.coffee:4:4)\ +`) + + expect(sourceStack.parsed).to.eql([ + { + message: 'Error: spec iframe stack', + whitespace: '', + }, + { + function: 'foo.bar', + fileUrl: 'http://localhost:1234/source_map_spec.js', + originalFile: 'cypress:////root/absolute/path/some_other_file.ts', + relativeFile: '/root/absolute/path/some_other_file.ts', + absoluteFile: '/root/absolute/path/some_other_file.ts', + line: 2, + column: 2, + whitespace: ' ', + }, + { + function: 'Context.', + fileUrl: 'http://localhost:1234/tests?p=cypress/integration/features/source_map_spec.js', + originalFile: 'webpack:////root/absolute/path/cypress/integration/features/source_map_spec.coffee', + relativeFile: '/root/absolute/path/cypress/integration/features/source_map_spec.coffee', + absoluteFile: '/root/absolute/path/cypress/integration/features/source_map_spec.coffee', + line: 4, + column: 4, + whitespace: ' ', + }, + ]) + }) + + it('returns empty object if there\'s no stack', () => { + expect($stackUtils.getSourceStack()).to.eql({}) + }) + }) + + context('.getSourceDetailsForFirstLine', () => { + it('parses good stack trace', () => { + const stack = stripIndent` + Error + at Suite.eval (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:101:3) + at Object../cypress/integration/spec.js (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:100:1) + at __webpack_require__ (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:20:30) + at Object.0 (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:119:18) + at __webpack_require__ (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:20:30) + at eval (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:84:18) + at eval (http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js:87:10) + at eval () + ` + const projectRoot = '/Users/gleb/git/cypress-example-todomvc' + const details = $stackUtils.getSourceDetailsForFirstLine(stack, projectRoot) + + expect(details.function, 'function name').to.equal('Suite.eval') + expect(details.fileUrl, 'file url').to.equal('http://localhost:8888/__cypress/tests?p=cypress/integration/spec.js') + }) + + it('parses anonymous eval line', () => { + const stack = stripIndent` + SyntaxError: The following error originated from your application code, not from Cypress. + + > Identifier 'app' has already been declared + + When Cypress detects uncaught errors originating from your application it will automatically fail the current test. + + This behavior is configurable, and you can choose to turn this off by listening to the \`uncaught:exception\` event. + SyntaxError: The following error originated from your application code, not from Cypress. + + > Identifier 'app' has already been declared + + When Cypress detects uncaught errors originating from your application it will automatically fail the current test. + + This behavior is configurable, and you can choose to turn this off by listening to the \`uncaught:exception\` event. + at :1:1 + at run (http://localhost:8888/node_modules/react/dist/JSXTransformer.js:184:10) + at check (http://localhost:8888/node_modules/react/dist/JSXTransformer.js:238:9) + at result..async (http://localhost:8888/node_modules/react/dist/JSXTransformer.js:273:9) + at XMLHttpRequest.xhr.onreadystatechange (http://localhost:8888/node_modules/react/dist/JSXTransformer.js:208:9) + From previous event: + at run (cypress:///../driver/src/cypress/cy.js:561:21) + at $Cy.cy. [as visit] (cypress:///../driver/src/cypress/cy.js:1018:11) + at Context.runnable.fn (cypress:///../driver/src/cypress/cy.js:1242:21) + at callFn (cypress:///../driver/node_modules/mocha/lib/runnable.js:395:21) + at Test.Runnable.run (cypress:///../driver/node_modules/mocha/lib/runnable.js:382:7) + at eval (cypress:///../driver/src/cypress/runner.js:1249:28) + From previous event: + at Object.onRunnableRun (cypress:///../driver/src/cypress/runner.js:1237:17) + at $Cypress.action (cypress:///../driver/src/cypress.js:397:28) + at Test.Runnable.run (cypress:///../driver/src/cypress/mocha.js:348:13) + at Runner.runTest (cypress:///../driver/node_modules/mocha/lib/runner.js:541:10) + at eval (cypress:///../driver/node_modules/mocha/lib/runner.js:667:12) + at next (cypress:///../driver/node_modules/mocha/lib/runner.js:450:14) + at eval (cypress:///../driver/node_modules/mocha/lib/runner.js:460:7) + at next (cypress:///../driver/node_modules/mocha/lib/runner.js:362:14) + at eval (cypress:///../driver/node_modules/mocha/lib/runner.js:428:5) + at timeslice (cypress:///../driver/node_modules/mocha/browser-entry.js:80:27) + ` + + const projectRoot = '/Users/gleb/git/cypress-example-todomvc' + const details = $stackUtils.getSourceDetailsForFirstLine(stack, projectRoot) + + expect(details, 'minimal details').to.deep.equal({ + absoluteFile: undefined, + column: 2, + fileUrl: undefined, + function: '', + line: 1, + originalFile: undefined, + relativeFile: undefined, + whitespace: ' ', + }) + }) + + // https://github.com/cypress-io/cypress/issues/14659 + it('parses stack trace with special characters', () => { + cy.stub($sourceMapUtils, 'getSourcePosition').returns({ + file: 'webpack:///cypress/integration/spec%with%20space%20&^$%20emoji%F0%9F%91%8D_%E4%BD%A0%E5%A5%BD.js', + line: 1, + column: 0, + }) + + // stack is fairly irrelevant in this test - testing transforming getSourcePosition response + const stack = stripIndent` + Error + at Object../cypress/integration/spec%with space &^$ emoji๐Ÿ‘_ไฝ ๅฅฝ.js (http://localhost:50129/__cypress/tests?p=cypress/integration/spec%25with%20space%20%26^$%20emoji๐Ÿ‘_ไฝ ๅฅฝ.js:99:1) + ` + + const projectRoot = '/Users/gleb/git/cypress-example-todomvc' + const details = $stackUtils.getSourceDetailsForFirstLine(stack, projectRoot) + + expect(details.originalFile).to.equal('webpack:///cypress/integration/spec%with space &^$ emoji๐Ÿ‘_ไฝ ๅฅฝ.js') + expect(details.relativeFile).to.equal('cypress/integration/spec%with space &^$ emoji๐Ÿ‘_ไฝ ๅฅฝ.js') + expect(details.absoluteFile).to.equal(`${projectRoot}/cypress/integration/spec%with space &^$ emoji๐Ÿ‘_ไฝ ๅฅฝ.js`) + }) + + it('maintains absolute path when provided', () => { + cy.stub($sourceMapUtils, 'getSourcePosition').returns({ + file: '/root/path/cypress/integration/spec.js', + line: 1, + column: 0, + }) + + // stack is fairly irrelevant in this test - testing transforming getSourcePosition response + const stack = stripIndent` + Error + at Object../cypress/integration/spec.js (http://localhost:50129/__cypress/tests?p=/root/path/cypress/integration/spec.js:99:1) + ` + + const projectRoot = '/Users/gleb/git/cypress-example-todomvc' + const details = $stackUtils.getSourceDetailsForFirstLine(stack, projectRoot) + + expect(details.originalFile).to.equal('/root/path/cypress/integration/spec.js') + expect(details.relativeFile).to.equal('/root/path/cypress/integration/spec.js') + expect(details.absoluteFile).to.equal(`/root/path/cypress/integration/spec.js`) + }) + }) + + context('.stackWithUserInvocationStackSpliced', () => { + let err + let userInvocationStack + + beforeEach(() => { + err = new Error(`\ +original message +original message line 2 +original message line 3`) + + err.stack = `\ +Error: original message +original message line 2 +original message line 3 + at originalStack1 (path/to/file:1:1) + at originalStack2 (path/to/file:1:1) + at __stackReplacementMarker (path/to/another:2:2) + at originalStack4 (path/to/file:1:1) + at originalStack5 (path/to/file:1:1)` + + userInvocationStack = `\ +user invocation message +user invocation message line 2 +user invocation message line 3 + at userStack1 (path/to/another:2:2) + at userStack2 (path/to/another:2:2)` + }) + + it('appends replaces the user invocation wrapper and all lines below it with the user invocation stack', () => { + const { stack } = $stackUtils.stackWithUserInvocationStackSpliced(err, userInvocationStack) + + expect(stack).to.equal(`\ +Error: original message +original message line 2 +original message line 3 + at originalStack1 (path/to/file:1:1) + at originalStack2 (path/to/file:1:1) +From Your Spec Code: + at userStack1 (path/to/another:2:2) + at userStack2 (path/to/another:2:2)`) + }) + + it('returns the index of where the user invocation is in the stack', () => { + const { index } = $stackUtils.stackWithUserInvocationStackSpliced(err, userInvocationStack) + + expect(index).to.equal(6) + }) + + it('appends at end when there is no stack replacement marker in the stack', () => { + err.stack = err.stack.replace(' at __stackReplacementMarker (path/to/another:2:2)\n', '') + + const { stack } = $stackUtils.stackWithUserInvocationStackSpliced(err, userInvocationStack) + + expect(stack).to.equal(`\ +Error: original message +original message line 2 +original message line 3 + at originalStack1 (path/to/file:1:1) + at originalStack2 (path/to/file:1:1) + at originalStack4 (path/to/file:1:1) + at originalStack5 (path/to/file:1:1) +From Your Spec Code: + at userStack1 (path/to/another:2:2) + at userStack2 (path/to/another:2:2)`) + }) + }) + + context('.stackWithoutMessage', () => { + it('returns stack with the foremost message lines', () => { + const stack = `\ +message 1 +message 2 + at stack1 (foo.js:1:1) +message 3 + at stack2 (bar.js:2:2)` + const result = $stackUtils.stackWithoutMessage(stack) + + expect(result).to.equal(`\ + at stack1 (foo.js:1:1) +message 3 + at stack2 (bar.js:2:2)`) + }) + }) + + context('.normalizedUserInvocationStack', () => { + it('removes message and cy[name] lines and normalizes indentation', () => { + const stack = `\ +message 1 +message 2 + at addCommand/cy[name]@cypress:///cy.js:0:0 + at stack1 (foo.js:1:1) + at stack2 (bar.js:2:2)` + const result = $stackUtils.normalizedUserInvocationStack(stack) + + expect(result).to.equal(`\ + at stack1 (foo.js:1:1) + at stack2 (bar.js:2:2)`) + }) + }) +}) diff --git a/packages/driver/cypress/integration/cypress/utils_spec.js b/packages/driver/cypress/e2e/cypress/utils.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/utils_spec.js rename to packages/driver/cypress/e2e/cypress/utils.cy.js diff --git a/packages/driver/cypress/integration/cypress/xml_http_request_spec.js b/packages/driver/cypress/e2e/cypress/xml_http_request.cy.js similarity index 100% rename from packages/driver/cypress/integration/cypress/xml_http_request_spec.js rename to packages/driver/cypress/e2e/cypress/xml_http_request.cy.js diff --git a/packages/driver/cypress/integration/dom/coordinates_spec.ts b/packages/driver/cypress/e2e/dom/coordinates.cy.ts similarity index 100% rename from packages/driver/cypress/integration/dom/coordinates_spec.ts rename to packages/driver/cypress/e2e/dom/coordinates.cy.ts diff --git a/packages/driver/cypress/integration/dom/elements_spec.ts b/packages/driver/cypress/e2e/dom/elements.cy.ts similarity index 100% rename from packages/driver/cypress/integration/dom/elements_spec.ts rename to packages/driver/cypress/e2e/dom/elements.cy.ts diff --git a/packages/driver/cypress/integration/dom/jquery_spec.ts b/packages/driver/cypress/e2e/dom/jquery.cy.ts similarity index 100% rename from packages/driver/cypress/integration/dom/jquery_spec.ts rename to packages/driver/cypress/e2e/dom/jquery.cy.ts diff --git a/packages/driver/cypress/integration/dom/visibility_spec.ts b/packages/driver/cypress/e2e/dom/visibility.cy.ts similarity index 100% rename from packages/driver/cypress/integration/dom/visibility_spec.ts rename to packages/driver/cypress/e2e/dom/visibility.cy.ts diff --git a/packages/driver/cypress/integration/dom/visibility_shadow_dom_spec.ts b/packages/driver/cypress/e2e/dom/visibility_shadow_dom.cy.ts similarity index 100% rename from packages/driver/cypress/integration/dom/visibility_shadow_dom_spec.ts rename to packages/driver/cypress/e2e/dom/visibility_shadow_dom.cy.ts diff --git a/packages/driver/cypress/integration/e2e/abort_beforeunload_event_spec.ts b/packages/driver/cypress/e2e/e2e/abort_beforeunload_event.cy.ts similarity index 100% rename from packages/driver/cypress/integration/e2e/abort_beforeunload_event_spec.ts rename to packages/driver/cypress/e2e/e2e/abort_beforeunload_event.cy.ts diff --git a/packages/driver/cypress/integration/e2e/abort_beforeunload_event_child_spec.ts b/packages/driver/cypress/e2e/e2e/abort_beforeunload_event_child.cy.ts similarity index 100% rename from packages/driver/cypress/integration/e2e/abort_beforeunload_event_child_spec.ts rename to packages/driver/cypress/e2e/e2e/abort_beforeunload_event_child.cy.ts diff --git a/packages/driver/cypress/integration/e2e/abort_onbeforeunload_spec.ts b/packages/driver/cypress/e2e/e2e/abort_onbeforeunload.cy.ts similarity index 100% rename from packages/driver/cypress/integration/e2e/abort_onbeforeunload_spec.ts rename to packages/driver/cypress/e2e/e2e/abort_onbeforeunload.cy.ts diff --git a/packages/driver/cypress/integration/e2e/abort_onbeforeunload_child_spec.ts b/packages/driver/cypress/e2e/e2e/abort_onbeforeunload_child.cy.ts similarity index 100% rename from packages/driver/cypress/integration/e2e/abort_onbeforeunload_child_spec.ts rename to packages/driver/cypress/e2e/e2e/abort_onbeforeunload_child.cy.ts diff --git a/packages/driver/cypress/integration/e2e/cancelation_spec.js b/packages/driver/cypress/e2e/e2e/cancelation.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/cancelation_spec.js rename to packages/driver/cypress/e2e/e2e/cancelation.cy.js diff --git a/packages/driver/cypress/integration/e2e/dom_hitbox_spec.js b/packages/driver/cypress/e2e/e2e/dom_hitbox.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/dom_hitbox_spec.js rename to packages/driver/cypress/e2e/e2e/dom_hitbox.cy.js diff --git a/packages/driver/cypress/integration/e2e/e2e_cookies_spec.js b/packages/driver/cypress/e2e/e2e/e2e_cookies.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/e2e_cookies_spec.js rename to packages/driver/cypress/e2e/e2e/e2e_cookies.cy.js diff --git a/packages/driver/cypress/integration/e2e/ended_early_spec.js b/packages/driver/cypress/e2e/e2e/ended_early.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/ended_early_spec.js rename to packages/driver/cypress/e2e/e2e/ended_early.cy.js diff --git a/packages/driver/cypress/integration/e2e/focus_blur_spec.js b/packages/driver/cypress/e2e/e2e/focus_blur.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/focus_blur_spec.js rename to packages/driver/cypress/e2e/e2e/focus_blur.cy.js diff --git a/packages/driver/cypress/integration/e2e/keyboard_spec.js b/packages/driver/cypress/e2e/e2e/keyboard.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/keyboard_spec.js rename to packages/driver/cypress/e2e/e2e/keyboard.cy.js diff --git a/packages/driver/cypress/integration/e2e/promises_spec.js b/packages/driver/cypress/e2e/e2e/promises.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/promises_spec.js rename to packages/driver/cypress/e2e/e2e/promises.cy.js diff --git a/packages/driver/cypress/integration/e2e/react-15_spec.js b/packages/driver/cypress/e2e/e2e/react-15.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/react-15_spec.js rename to packages/driver/cypress/e2e/e2e/react-15.cy.js diff --git a/packages/driver/cypress/integration/e2e/react-16_spec.js b/packages/driver/cypress/e2e/e2e/react-16.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/react-16_spec.js rename to packages/driver/cypress/e2e/e2e/react-16.cy.js diff --git a/packages/driver/cypress/integration/e2e/redirects_spec.js b/packages/driver/cypress/e2e/e2e/redirects.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/redirects_spec.js rename to packages/driver/cypress/e2e/e2e/redirects.cy.js diff --git a/packages/driver/cypress/e2e/e2e/rerun.cy.js b/packages/driver/cypress/e2e/e2e/rerun.cy.js new file mode 100644 index 0000000000..3c2ac08cd1 --- /dev/null +++ b/packages/driver/cypress/e2e/e2e/rerun.cy.js @@ -0,0 +1,52 @@ +// NOTE: we could clean up this test a lot +// by probably using preserve:run:state event +// or by using localstorage + +// store these on our outer top window +// so they are globally preserved +if (window.top.runCount == null) { + window.top.runCount = 0 +} + +const isTextTerminal = Cypress.config('isTextTerminal') + +describe('rerun state bugs', () => { + // NOTE: there's probably other ways to cause a re-run + // event more programatically (like firing it through Cypress) + // but we get the hashchange coverage for free on this. + it('stores viewport globally and does not hang on re-runs', () => { + cy.viewport(500, 500).then(() => { + window.top.runCount++ + if (window.top.runCount === 1) { + // turn off mocha events for a second + Cypress.config('isTextTerminal', false) + + // cause a rerun event to occur by triggering a hash change + window.top.dispatchEvent(new Event('test:trigger:rerun')) + } else if (window.top.runCount === 2) { + // Second time, do nothing, with mocha events still disabled + } else { + // 3rd time around + // let the mocha end events fire if they're supposed to + Cypress.config('isTextTerminal', isTextTerminal) + } + }) + }) + + it('does nothing if there is no runner', () => { + // https://github.com/cypress-io/cypress/issues/7968 + cy.stub(Cypress.cy, 'stop') + const runner = Cypress.runner + + Cypress.runner = null + + Cypress.stop() + + const stopWasCalled = Cypress.cy.stop.called + + Cypress.runner = runner + Cypress.cy.stop.restore() + + expect(stopWasCalled).to.be.false + }) +}) diff --git a/packages/driver/cypress/integration/e2e/return_value_spec.js b/packages/driver/cypress/e2e/e2e/return_value.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/return_value_spec.js rename to packages/driver/cypress/e2e/e2e/return_value.cy.js diff --git a/packages/driver/cypress/integration/e2e/security_spec.js b/packages/driver/cypress/e2e/e2e/security.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/security_spec.js rename to packages/driver/cypress/e2e/e2e/security.cy.js diff --git a/packages/driver/cypress/integration/e2e/testConfigOverrides-describe-only_spec.js b/packages/driver/cypress/e2e/e2e/testConfigOverrides-describe-only.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/testConfigOverrides-describe-only_spec.js rename to packages/driver/cypress/e2e/e2e/testConfigOverrides-describe-only.cy.js diff --git a/packages/driver/cypress/integration/e2e/testConfigOverrides-it-only_spec.js b/packages/driver/cypress/e2e/e2e/testConfigOverrides-it-only.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/testConfigOverrides-it-only_spec.js rename to packages/driver/cypress/e2e/e2e/testConfigOverrides-it-only.cy.js diff --git a/packages/driver/cypress/integration/e2e/testConfigOverrides_spec.js b/packages/driver/cypress/e2e/e2e/testConfigOverrides.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/testConfigOverrides_spec.js rename to packages/driver/cypress/e2e/e2e/testConfigOverrides.cy.js diff --git a/packages/driver/cypress/integration/e2e/text_mask_spec.js b/packages/driver/cypress/e2e/e2e/text_mask.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/text_mask_spec.js rename to packages/driver/cypress/e2e/e2e/text_mask.cy.js diff --git a/packages/driver/cypress/integration/e2e/uncaught_errors_spec.js b/packages/driver/cypress/e2e/e2e/uncaught_errors.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/uncaught_errors_spec.js rename to packages/driver/cypress/e2e/e2e/uncaught_errors.cy.js diff --git a/packages/driver/cypress/integration/e2e/video_spec.js b/packages/driver/cypress/e2e/e2e/video.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/video_spec.js rename to packages/driver/cypress/e2e/e2e/video.cy.js diff --git a/packages/driver/cypress/integration/e2e/visibility_spec.js b/packages/driver/cypress/e2e/e2e/visibility.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/visibility_spec.js rename to packages/driver/cypress/e2e/e2e/visibility.cy.js diff --git a/packages/driver/cypress/integration/e2e/webcam_spec.js b/packages/driver/cypress/e2e/e2e/webcam.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/webcam_spec.js rename to packages/driver/cypress/e2e/e2e/webcam.cy.js diff --git a/packages/driver/cypress/integration/e2e/zonejs_spec.js b/packages/driver/cypress/e2e/e2e/zonejs.cy.js similarity index 100% rename from packages/driver/cypress/integration/e2e/zonejs_spec.js rename to packages/driver/cypress/e2e/e2e/zonejs.cy.js diff --git a/packages/driver/cypress/integration/issues/1119_spec.js b/packages/driver/cypress/e2e/issues/1119.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1119_spec.js rename to packages/driver/cypress/e2e/issues/1119.cy.js diff --git a/packages/driver/cypress/integration/issues/1244_spec.js b/packages/driver/cypress/e2e/issues/1244.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1244_spec.js rename to packages/driver/cypress/e2e/issues/1244.cy.js diff --git a/packages/driver/cypress/integration/issues/1436_spec.js b/packages/driver/cypress/e2e/issues/1436.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1436_spec.js rename to packages/driver/cypress/e2e/issues/1436.cy.js diff --git a/packages/driver/cypress/integration/issues/17512_spec.js b/packages/driver/cypress/e2e/issues/17512.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/17512_spec.js rename to packages/driver/cypress/e2e/issues/17512.cy.js diff --git a/packages/driver/cypress/integration/issues/1854_spec.js b/packages/driver/cypress/e2e/issues/1854.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1854_spec.js rename to packages/driver/cypress/e2e/issues/1854.cy.js diff --git a/packages/driver/cypress/integration/issues/18805_spec.js b/packages/driver/cypress/e2e/issues/18805.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/18805_spec.js rename to packages/driver/cypress/e2e/issues/18805.cy.js diff --git a/packages/driver/cypress/integration/issues/1909_spec.js b/packages/driver/cypress/e2e/issues/1909.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1909_spec.js rename to packages/driver/cypress/e2e/issues/1909.cy.js diff --git a/packages/driver/cypress/integration/issues/1939_1940_2190_spec.js b/packages/driver/cypress/e2e/issues/1939_1940_2190.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/1939_1940_2190_spec.js rename to packages/driver/cypress/e2e/issues/1939_1940_2190.cy.js diff --git a/packages/driver/cypress/integration/issues/2034_spec.js b/packages/driver/cypress/e2e/issues/2034.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/2034_spec.js rename to packages/driver/cypress/e2e/issues/2034.cy.js diff --git a/packages/driver/cypress/integration/issues/2582_spec.js b/packages/driver/cypress/e2e/issues/2582.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/2582_spec.js rename to packages/driver/cypress/e2e/issues/2582.cy.js diff --git a/packages/driver/cypress/integration/issues/2784_spec.js b/packages/driver/cypress/e2e/issues/2784.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/2784_spec.js rename to packages/driver/cypress/e2e/issues/2784.cy.js diff --git a/packages/driver/cypress/integration/issues/2850_spec.js b/packages/driver/cypress/e2e/issues/2850.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/2850_spec.js rename to packages/driver/cypress/e2e/issues/2850.cy.js diff --git a/packages/driver/cypress/integration/issues/3253_spec.js b/packages/driver/cypress/e2e/issues/3253.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/3253_spec.js rename to packages/driver/cypress/e2e/issues/3253.cy.js diff --git a/packages/driver/cypress/integration/issues/3847_spec.js b/packages/driver/cypress/e2e/issues/3847.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/3847_spec.js rename to packages/driver/cypress/e2e/issues/3847.cy.js diff --git a/packages/driver/cypress/integration/issues/3871_spec.js b/packages/driver/cypress/e2e/issues/3871.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/3871_spec.js rename to packages/driver/cypress/e2e/issues/3871.cy.js diff --git a/packages/driver/cypress/integration/issues/3890_spec.js b/packages/driver/cypress/e2e/issues/3890.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/3890_spec.js rename to packages/driver/cypress/e2e/issues/3890.cy.js diff --git a/packages/driver/cypress/integration/issues/3975_spec.js b/packages/driver/cypress/e2e/issues/3975.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/3975_spec.js rename to packages/driver/cypress/e2e/issues/3975.cy.js diff --git a/packages/driver/cypress/integration/issues/4295_spec.js b/packages/driver/cypress/e2e/issues/4295.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/4295_spec.js rename to packages/driver/cypress/e2e/issues/4295.cy.js diff --git a/packages/driver/cypress/integration/issues/4373_spec.js b/packages/driver/cypress/e2e/issues/4373.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/4373_spec.js rename to packages/driver/cypress/e2e/issues/4373.cy.js diff --git a/packages/driver/cypress/integration/issues/510_spec.js b/packages/driver/cypress/e2e/issues/510.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/510_spec.js rename to packages/driver/cypress/e2e/issues/510.cy.js diff --git a/packages/driver/cypress/integration/issues/565_spec.js b/packages/driver/cypress/e2e/issues/565.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/565_spec.js rename to packages/driver/cypress/e2e/issues/565.cy.js diff --git a/packages/driver/cypress/integration/issues/5682_spec.js b/packages/driver/cypress/e2e/issues/5682.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/5682_spec.js rename to packages/driver/cypress/e2e/issues/5682.cy.js diff --git a/packages/driver/cypress/integration/issues/5707_spec.js b/packages/driver/cypress/e2e/issues/5707.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/5707_spec.js rename to packages/driver/cypress/e2e/issues/5707.cy.js diff --git a/packages/driver/cypress/integration/issues/573_spec.js b/packages/driver/cypress/e2e/issues/573.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/573_spec.js rename to packages/driver/cypress/e2e/issues/573.cy.js diff --git a/packages/driver/cypress/integration/issues/599_spec.js b/packages/driver/cypress/e2e/issues/599.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/599_spec.js rename to packages/driver/cypress/e2e/issues/599.cy.js diff --git a/packages/driver/cypress/integration/issues/6412_spec.ts b/packages/driver/cypress/e2e/issues/6412.cy.ts similarity index 100% rename from packages/driver/cypress/integration/issues/6412_spec.ts rename to packages/driver/cypress/e2e/issues/6412.cy.ts diff --git a/packages/driver/cypress/integration/issues/652_spec.js b/packages/driver/cypress/e2e/issues/652.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/652_spec.js rename to packages/driver/cypress/e2e/issues/652.cy.js diff --git a/packages/driver/cypress/integration/issues/7170_spec.js b/packages/driver/cypress/e2e/issues/7170.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/7170_spec.js rename to packages/driver/cypress/e2e/issues/7170.cy.js diff --git a/packages/driver/cypress/integration/issues/761_2968_3973_spec.js b/packages/driver/cypress/e2e/issues/761_2968_3973.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/761_2968_3973_spec.js rename to packages/driver/cypress/e2e/issues/761_2968_3973.cy.js diff --git a/packages/driver/cypress/integration/issues/8279_spec.js b/packages/driver/cypress/e2e/issues/8279.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/8279_spec.js rename to packages/driver/cypress/e2e/issues/8279.cy.js diff --git a/packages/driver/cypress/integration/issues/8998_spec.js b/packages/driver/cypress/e2e/issues/8998.cy.js similarity index 100% rename from packages/driver/cypress/integration/issues/8998_spec.js rename to packages/driver/cypress/e2e/issues/8998.cy.js diff --git a/packages/driver/cypress/integration/util/blob_spec.js b/packages/driver/cypress/e2e/util/blob.cy.js similarity index 100% rename from packages/driver/cypress/integration/util/blob_spec.js rename to packages/driver/cypress/e2e/util/blob.cy.js diff --git a/packages/driver/cypress/integration/util/buffer_spec.js b/packages/driver/cypress/e2e/util/buffer.cy.js similarity index 100% rename from packages/driver/cypress/integration/util/buffer_spec.js rename to packages/driver/cypress/e2e/util/buffer.cy.js diff --git a/packages/driver/cypress/integration/util/limited_map_spec.js b/packages/driver/cypress/e2e/util/limited_map.cy.js similarity index 100% rename from packages/driver/cypress/integration/util/limited_map_spec.js rename to packages/driver/cypress/e2e/util/limited_map.cy.js diff --git a/packages/driver/cypress/integration/util/queue_spec.ts b/packages/driver/cypress/e2e/util/queue.cy.ts similarity index 100% rename from packages/driver/cypress/integration/util/queue_spec.ts rename to packages/driver/cypress/e2e/util/queue.cy.ts diff --git a/packages/driver/cypress/fixtures/fileSpec.json b/packages/driver/cypress/fixtures/fileSpec.json new file mode 100644 index 0000000000..da4f53f4b1 --- /dev/null +++ b/packages/driver/cypress/fixtures/fileSpec.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "http://localhost:3500" +} \ No newline at end of file diff --git a/packages/driver/cypress/integration/commands/actions/trigger_spec.js b/packages/driver/cypress/integration/commands/actions/trigger_spec.js deleted file mode 100644 index 0bde9d654f..0000000000 --- a/packages/driver/cypress/integration/commands/actions/trigger_spec.js +++ /dev/null @@ -1,1281 +0,0 @@ -const { assertLogLength } = require('../../../support/utils') -const { _, $ } = Cypress - -describe('src/cy/commands/actions/trigger', () => { - before(() => { - cy - .visit('/fixtures/dom.html') - .then(function (win) { - this.body = win.document.body.outerHTML - }) - }) - - beforeEach(function () { - const doc = cy.state('document') - - $(doc.body).empty().html(this.body) - }) - - context('#trigger', () => { - it('sends event', (done) => { - const $btn = cy.$$('#button') - - $btn.on('mouseover', (e) => { - const { fromElViewport } = Cypress.dom.getElementCoordinatesByPosition($btn) - - const obj = _.pick(e.originalEvent, 'bubbles', 'cancelable', 'target', 'type') - - expect(obj).to.deep.eq({ - bubbles: true, - cancelable: true, - target: $btn.get(0), - type: 'mouseover', - }) - - expect(e.clientX).to.be.closeTo(fromElViewport.x, 1) - expect(e.clientY).to.be.closeTo(fromElViewport.y, 1) - - done() - }) - - cy.get('#button').trigger('mouseover') - }) - - it('bubbles up event by default', (done) => { - cy - .window() - .then((win) => { - $(win).one('mouseover', () => { - done() - }) - - cy.get('#button').trigger('mouseover') - }) - }) - - it('does not bubble up event if specified', (done) => { - cy - .window() - .then((win) => { - const $win = $(win) - - $win.on('keydown', (e) => { - const evt = JSON.stringify(e.originalEvent, [ - 'bubbles', 'cancelable', 'isTrusted', 'type', 'clientX', 'clientY', - ]) - - done(new Error(`event should not have bubbled up to window listener: ${evt}`)) - }) - - cy - .get('#button') - .trigger('keydown', { - bubbles: false, - }) - .then(() => { - $win.off('keydown') - - done() - }) - }) - }) - - it('sends through event options, overriding defaults', (done) => { - let options = { - clientX: 42, - clientY: 24, - pageX: 420, - pageY: 240, - foo: 'foo', - } - - cy.$$('button:first').on('mouseover', (e) => { - const eventOptions = _.pick(e.originalEvent, 'clientX', 'clientY', 'pageX', 'pageY', 'foo') - - expect(eventOptions).to.eql(options) - - done() - }) - - cy.get('button:first').trigger('mouseover', options) - }) - - it('records correct clientX when el scrolled', (done) => { - const $btn = $('').appendTo(cy.$$('body')) - const win = cy.state('window') - - $btn.on('mouseover', (e) => { - const { fromElViewport } = Cypress.dom.getElementCoordinatesByPosition($btn) - - expect(win.scrollX).to.be.gt(0) - expect(e.clientX).to.be.closeTo(fromElViewport.x, 1) - - done() - }) - - cy.get('#scrolledBtn').trigger('mouseover') - }) - - it('records correct clientY when el scrolled', (done) => { - const $btn = $('').appendTo(cy.$$('body')) - const win = cy.state('window') - - $btn.on('mouseover', (e) => { - const { fromElViewport } = Cypress.dom.getElementCoordinatesByPosition($btn) - - expect(win.scrollX).to.be.gt(0) - expect(e.clientY).to.be.closeTo(fromElViewport.y, 1) - - done() - }) - - cy.get('#scrolledBtn').trigger('mouseover') - }) - - // NOTE: flaky about 50% of the time in Firefox... - // temporarily skipping for now, but this needs - // to be reenabled after launch once we have time - // to look at the underlying failure cause - it.skip('records correct pageX and pageY el scrolled', (done) => { - const $btn = $('').appendTo(cy.$$('body')) - - const win = cy.state('window') - - $btn.on('mouseover', (e) => { - expect(e.pageX).to.be.closeTo(win.scrollX + e.clientX, 1) - expect(e.pageY).to.be.closeTo(win.scrollY + e.clientY, 1) - - done() - }) - - cy.get('#scrolledBtn').trigger('mouseover') - }) - - it('does not change the subject', () => { - const $input = cy.$$('input:first') - - cy.get('input:first').trigger('keydown').then(($el) => { - expect($el.get(0)).to.eq($input.get(0)) - }) - }) - - it('can trigger events on the window', () => { - let expected = false - - const win = cy.state('window') - - $(win).on('scroll', (e) => { - expected = true - }) - - cy - .window().trigger('scroll') - .then(() => { - expect(expected).to.be.true - }) - }) - - it('can trigger custom events on the window', () => { - let expected = false - - const win = cy.state('window') - - $(win).on('foo', (e) => { - expect(e.detail).to.deep.eq({ foo: 'bar' }) - expected = true - }) - - cy - .window().trigger('foo', { - detail: { foo: 'bar' }, - }) - .then(() => { - expect(expected).to.be.true - }) - }) - - it('can trigger events on the document', () => { - let expected = false - - const doc = cy.state('document') - - $(doc).on('dragover', () => { - expected = true - }) - - cy.document().trigger('dragover').then(() => { - expect(expected).to.be.true - }) - }) - - it('can handle window w/length > 1 as a subject', () => { - cy.window().should('have.length.gt', 1).trigger('click') - }) - - // https://github.com/cypress-io/cypress/issues/3686 - it('view should be AUT window', (done) => { - cy.window().then((win) => { - cy.get('input:first').then((jQueryElement) => { - let elem = jQueryElement.get(0) - - elem.addEventListener('mousedown', (event) => { - expect(event.view).to.eql(win) - done() - }) - }) - }) - - cy.get('input:first').trigger('mousedown', { - eventConstructor: 'MouseEvent', - button: 0, - shiftKey: false, - ctrlKey: false, - }) - }) - - describe('actionability', () => { - it('can trigger on elements which are hidden until scrolled within parent container', () => { - cy.get('#overflow-auto-container').contains('quux').trigger('mousedown') - }) - - it('can trigger on elements with `opacity: 0`', () => { - cy.get('#opacity-0').trigger('mousedown') - }) - - it('can trigger on elements with parents that have `opacity: 0`', () => { - cy.get('#opacity-0-parent').trigger('mousedown') - }) - - it('can trigger on readonly inputs', () => { - cy.get('#readonly-attr').trigger('mousedown') - }) - - it('does not scroll when being forced', () => { - const scrolled = [] - - cy.on('scrolled', ($el, type) => { - scrolled.push(type) - }) - - cy - .get('button:last').trigger('mouseover', { force: true }) - .then(() => { - expect(scrolled).to.be.empty - }) - }) - - it('can force trigger on hidden elements', () => { - cy.get('button:first').invoke('hide').trigger('tap', { force: true }) - }) - - it('can force trigger on disabled elements', () => { - cy.get('input:first').invoke('prop', 'disabled', true).trigger('tap', { force: true }) - }) - - it('can forcibly trigger even when being covered by another element', () => { - const $btn = $('').attr('id', 'button-covered-in-span').prependTo(cy.$$('body')) - - $('span on button').css({ position: 'absolute', left: $btn.offset().left, top: $btn.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo(cy.$$('body')) - - const scrolled = [] - let retried = false - let tapped = false - - cy.on('scrolled', ($el, type) => { - scrolled.push(type) - }) - - cy.on('command:retry', ($el, type) => { - retried = true - }) - - $btn.on('tap', () => { - tapped = true - }) - - cy.get('#button-covered-in-span').trigger('tap', { force: true }).then(() => { - expect(scrolled).to.be.empty - expect(retried).to.be.false - expect(tapped).to.be.true - }) - }) - - it('eventually triggers when covered up', () => { - const $btn = $('') - .attr('id', 'button-covered-in-span') - .prependTo(cy.$$('body')) - - const $span = $('span on button').css({ - position: 'absolute', - left: $btn.offset().left, - top: $btn.offset().top, - padding: 5, - display: 'inline-block', - backgroundColor: 'yellow', - }) - .prependTo(cy.$$('body')) - - const scrolled = [] - let retried = false - - cy.on('scrolled', ($el, type) => { - return scrolled.push(type) - }) - - cy.on('command:retry', _.after(3, () => { - $span.hide() - retried = true - })) - - cy.get('#button-covered-in-span').trigger('mousedown').then(() => { - expect(retried).to.be.true - - // - element scrollIntoView - // - element scrollIntoView (retry animation coords) - // - element scrollIntoView (retry covered) - // - element scrollIntoView (retry covered) - // - window - expect(scrolled).to.deep.eq(['element', 'element', 'element', 'element']) - }) - }) - - it('issues event to descendent', () => { - let mouseovers = 0 - - const $btn = $('
', { - id: 'div-covered-in-span', - }) - .css({ padding: 10, margin: 0, border: 'solid 1px #000' }) - .prependTo(cy.$$('body')) - - const $span = $('span covering div') - .css({ padding: 5, display: 'block', backgroundColor: 'yellow' }) - .appendTo($btn) - - $btn.on('mouseover', () => { - mouseovers += 1 - }) - - $span.on('mouseover', () => { - mouseovers += 1 - }) - - cy - .get('#div-covered-in-span').trigger('mouseover') - .should(() => { - expect(mouseovers).to.eq(2) - }) - }) - - it('issues event to descendent when waitForAnimations is false', { waitForAnimations: false }, () => { - let mouseovers = 0 - - const $btn = $('
', { - id: 'div-covered-in-span', - }) - .css({ padding: 10, margin: 0, border: 'solid 1px #000' }) - .prependTo(cy.$$('body')) - - const $span = $('span covering div') - .css({ padding: 5, display: 'block', backgroundColor: 'yellow' }) - .appendTo($btn) - - $btn.on('mouseover', () => { - mouseovers += 1 - }) - - $span.on('mouseover', () => { - mouseovers += 1 - }) - - cy - .get('#div-covered-in-span').trigger('mouseover') - .should(() => { - expect(mouseovers).to.eq(2) - }) - }) - - it('scrolls the window past a fixed position element when being covered', () => { - $('') - .attr('id', 'button-covered-in-nav') - .appendTo(cy.$$('#fixed-nav-test')) - - $('') - .css({ - position: 'fixed', - left: 0, - top: 0, - padding: 20, - backgroundColor: 'yellow', - zIndex: 1, - }) - .prependTo(cy.$$('body')) - - const scrolled = [] - - cy.on('scrolled', ($el, type) => { - return scrolled.push(type) - }) - - cy.get('#button-covered-in-nav').trigger('mouseover').then(() => { - // - element scrollIntoView - // - element scrollIntoView (retry animation coords) - // - window - expect(scrolled).to.deep.eq(['element', 'element', 'window']) - }) - }) - - it('scrolls the window past two fixed positioned elements when being covered', () => { - $('') - .attr('id', 'button-covered-in-nav') - .appendTo(cy.$$('#fixed-nav-test')) - - $('') - .css({ - position: 'fixed', - left: 0, - top: 0, - padding: 20, - backgroundColor: 'yellow', - zIndex: 1, - }) - .prependTo(cy.$$('body')) - - $('') - .css({ - position: 'fixed', - left: 0, - top: 40, - padding: 20, - backgroundColor: 'red', - zIndex: 1, - }) - .prependTo(cy.$$('body')) - - const scrolled = [] - - cy.on('scrolled', ($el, type) => { - return scrolled.push(type) - }) - - cy.get('#button-covered-in-nav').trigger('mouseover').then(() => { - // - element scrollIntoView - // - element scrollIntoView (retry animation coords) - // - window (nav1) - // - window (nav2) - expect(scrolled).to.deep.eq(['element', 'element', 'window', 'window']) - }) - }) - - it('scrolls a container past a fixed position element when being covered', () => { - cy.viewport(600, 450) - - const $body = cy.$$('body') - - // we must remove all of our children to - // prevent the window from scrolling - $body.children().remove() - - // this tests that our container properly scrolls! - const $container = $('
') - .attr('id', 'scrollable-container') - .css({ - position: 'relative', - width: 300, - height: 200, - marginBottom: 100, - backgroundColor: 'green', - overflow: 'auto', - }) - .prependTo($body) - - $('') - .attr('id', 'button-covered-in-nav') - .css({ - marginTop: 500, - // marginLeft: 500 - marginBottom: 500, - }) - .appendTo($container) - - $('') - .css({ - position: 'fixed', - left: 0, - top: 0, - padding: 20, - backgroundColor: 'yellow', - zIndex: 1, - }) - .prependTo($container) - - const scrolled = [] - - cy.on('scrolled', ($el, type) => { - scrolled.push(type) - }) - - cy.get('#button-covered-in-nav').trigger('mouseover').then(() => { - // - element scrollIntoView - // - element scrollIntoView (retry animation coords) - // - window - // - container - expect(scrolled).to.deep.eq(['element', 'element', 'window', 'container']) - }) - }) - - it('waits until element becomes visible', () => { - const $btn = cy.$$('#button').hide() - - let retried = false - - cy.on('command:retry', _.after(3, () => { - $btn.show() - retried = true - })) - - cy.get('#button').trigger('mouseover').then(() => { - expect(retried).to.be.true - }) - }) - - it('waits until element is no longer disabled', () => { - const $btn = cy.$$('#button').prop('disabled', true) - - let retried = false - let mouseovers = 0 - - $btn.on('mouseover', () => { - mouseovers += 1 - }) - - cy.on('command:retry', _.after(3, () => { - $btn.prop('disabled', false) - retried = true - })) - - cy.get('#button').trigger('mouseover').then(() => { - expect(mouseovers).to.eq(1) - expect(retried).to.be.true - }) - }) - - it('waits until element stops animating', () => { - let retries = 0 - - cy.on('command:retry', (obj) => { - retries += 1 - }) - - cy.stub(cy, 'ensureElementIsNotAnimating') - .throws(new Error('animating!')) - .onThirdCall().returns() - - cy.get('button:first').trigger('mouseover').then(() => { - // - retry animation coords - // - retry animation - // - retry animation - expect(retries).to.eq(3) - expect(cy.ensureElementIsNotAnimating).to.be.calledThrice - }) - }) - - it('does not throw when waiting for animations is disabled', { - waitForAnimations: false, - }, () => { - cy.stub(cy, 'ensureElementIsNotAnimating').throws(new Error('animating!')) - - cy.get('button:first').trigger('mouseover').then(() => { - expect(cy.ensureElementIsNotAnimating).not.to.be.called - }) - }) - - it('does not throw when turning off waitForAnimations in options', () => { - cy.stub(cy, 'ensureElementIsNotAnimating').throws(new Error('animating!')) - - cy.get('button:first').trigger('tap', { waitForAnimations: false }).then(() => { - expect(cy.ensureElementIsNotAnimating).not.to.be.called - }) - }) - - it('passes options.animationDistanceThreshold to cy.ensureElementIsNotAnimating', () => { - const $btn = cy.$$('button:first') - - const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($btn) - - cy.spy(cy, 'ensureElementIsNotAnimating') - - cy.get('button:first').trigger('tap', { animationDistanceThreshold: 1000 }).then(() => { - const { args } = cy.ensureElementIsNotAnimating.firstCall - - expect(args[1]).to.deep.eq([fromElWindow, fromElWindow]) - expect(args[2]).to.eq(1000) - }) - }) - - it('passes config.animationDistanceThreshold to cy.ensureElementIsNotAnimating', () => { - const animationDistanceThreshold = Cypress.config('animationDistanceThreshold') - - const $btn = cy.$$('button:first') - - const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($btn) - - cy.spy(cy, 'ensureElementIsNotAnimating') - - cy.get('button:first').trigger('mouseover').then(() => { - const { args } = cy.ensureElementIsNotAnimating.firstCall - - expect(args[1]).to.deep.eq([fromElWindow, fromElWindow]) - expect(args[2]).to.eq(animationDistanceThreshold) - }) - }) - - it('can specify scrollBehavior in options', () => { - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover', { scrollBehavior: 'bottom' }) - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).to.be.calledWith({ block: 'end' }) - }) - }) - - it('does not scroll when scrollBehavior is false in options', () => { - cy.scrollTo('top') - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover', { scrollBehavior: false }) - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).not.to.be.called - }) - }) - - it('can specify scrollBehavior bottom in config', { scrollBehavior: 'bottom' }, () => { - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover') - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).to.be.calledWith({ block: 'end' }) - }) - }) - - it('can specify scrollBehavior center in config', { scrollBehavior: 'center' }, () => { - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover') - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).to.be.calledWith({ block: 'center' }) - }) - }) - - it('can specify scrollBehavior nearest in config', { scrollBehavior: 'nearest' }, () => { - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover') - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).to.be.calledWith({ block: 'nearest' }) - }) - }) - - it('does not scroll when scrollBehavior is false in config', { scrollBehavior: false }, () => { - cy.scrollTo('top') - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover') - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).not.to.be.called - }) - }) - - it('calls scrollIntoView by default', () => { - cy.scrollTo('top') - cy.get('button:first').then((el) => { - cy.spy(el[0], 'scrollIntoView') - }) - - cy.get('button:first').trigger('mouseover') - - cy.get('button:first').then((el) => { - expect(el[0].scrollIntoView).to.be.calledWith({ block: 'start' }) - }) - }) - - // https://github.com/cypress-io/cypress/issues/4233 - it('can check an element behind a sticky header', () => { - cy.viewport(400, 400) - cy.visit('./fixtures/sticky-header.html') - cy.get('p').trigger('mouseover') - }) - - it('errors when scrollBehavior is false and element is out of view and is clicked', (done) => { - cy.scrollTo('top') - - cy.on('fail', (err) => { - expect(err.message).to.include('`cy.trigger()` failed because the center of this element is hidden from view') - expect(cy.state('window').scrollY).to.equal(0) - expect(cy.state('window').scrollX).to.equal(0) - - done() - }) - - // make sure the input is out of view - const $body = cy.$$('body') - - $('
Long block 5
') - .css({ - height: '500px', - border: '1px solid red', - marginTop: '10px', - width: '100%', - }).prependTo($body) - - cy.get('button:first').trigger('mouseover', { scrollBehavior: false, timeout: 200 }) - }) - }) - - describe('assertion verification', { - defaultCommandTimeout: 100, - }, () => { - beforeEach(function () { - cy.on('log:added', (attrs, log) => { - if (log.get('name') === 'assert') { - this.lastLog = log - } - }) - - return null - }) - - it('eventually passes the assertion', () => { - const $btn = cy.$$('button:first') - - cy.on('command:retry', _.once(() => { - $btn.addClass('moused-over') - })) - - cy.get('button:first').trigger('mouseover').should('have.class', 'moused-over').then(function () { - const { lastLog } = this - - expect(lastLog.get('name')).to.eq('assert') - expect(lastLog.get('state')).to.eq('passed') - expect(lastLog.get('ended')).to.be.true - }) - }) - }) - - describe('position argument', () => { - it('can trigger event on center by default', (done) => { - const $button = cy.$$(' + + + + + + + +
+ )) + + cy.percySnapshot() + }) + + it('can render an external link', () => { + cy.mount(() => ( + + )) + + cy.contains('a', 'test').should('have.attr', 'data-cy', 'external') + }) + + it('can render an internal link', () => { + cy.mount(() => ( + + )) + + cy.contains('a', 'test').should('have.attr', 'href', '/test') + cy.contains('a', 'test').should('not.have.attr', 'data-cy', 'external') + cy.contains('a', 'test').should('not.have.attr', 'aria-disabled') + cy.contains('a', 'test').should('not.have.attr', 'role', 'link') + }) + + it('can render a Router Link', () => { + const router = createRouter({ + history: createWebHistory(), + routes: [], + }) + + cy.mount(() => ( + + ), { + global: { + plugins: [router], + }, + }) + + cy.contains('a', 'test') + .should('have.attr', 'href') + .and('include', '/test?example=param') + }) + + it('renders button as disabled with disabled prop', () => { + cy.mount(() => ( + + )) + + cy.contains('button', 'test').should('be.disabled') + }) + + // context for disabled link pattern: https://www.scottohara.me/blog/2021/05/28/disabled-links.html + it('handles "disabled" links', () => { + cy.mount(() => ( + + )) + + cy.contains('a', 'test').should('not.have.attr', 'href') + cy.contains('a', 'test').should('have.attr', 'aria-disabled') + cy.contains('a', 'test').should('have.attr', 'role', 'link') + }) + + it('renders prefix icon', () => { + cy.mount(() => ( + + )) + + cy.get('[data-cy="coffee-icon"]').should('be.visible') + }) +}) diff --git a/packages/frontend-shared/src/components/Button.vue b/packages/frontend-shared/src/components/Button.vue new file mode 100644 index 0000000000..36614e85de --- /dev/null +++ b/packages/frontend-shared/src/components/Button.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/packages/frontend-shared/src/components/ButtonInternals.vue b/packages/frontend-shared/src/components/ButtonInternals.vue new file mode 100644 index 0000000000..f2a46a4152 --- /dev/null +++ b/packages/frontend-shared/src/components/ButtonInternals.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/packages/frontend-shared/src/components/Card.cy.tsx b/packages/frontend-shared/src/components/Card.cy.tsx new file mode 100644 index 0000000000..24e490e784 --- /dev/null +++ b/packages/frontend-shared/src/components/Card.cy.tsx @@ -0,0 +1,107 @@ +import Card from './Card.vue' +import IconE2E from '~icons/cy/testing-type-e2e_x64.svg' +import IconE2ESolid from '~icons/cy/testing-type-e2e-solid_x64.svg' +import IconComponent from '~icons/cy/testing-type-component_x64.svg' +import IconComponentSolid from '~icons/cy/testing-type-component-solid_x64.svg' + +describe('Card', { viewportHeight: 400 }, () => { + it('renders with icons, text, and focus state', () => { + const e2eTitle = 'E2E Testing' + const e2eDescription = 'Build and test the entire experience of your application from end-to-end to ensure each flow matches your expectations.' + const ctTitle = 'Component Testing' + const ctDescription = 'Build and test your components from your design system in isolation in order to ensure each state matches your expectations.' + + cy.mount(() => { + const clickSpy = cy.spy().as('clickSpy') + + return (
+ + +
) + }) + + cy.contains('button', e2eTitle) + .as('e2eTitle') + .should('be.visible') + .and('not.be.disabled') + + cy.contains(e2eDescription).should('be.visible') + + cy.contains('button', ctTitle) + .as('ctTitle') + .should('be.visible') + .and('not.be.disabled') + + cy.contains(ctDescription).should('be.visible') + + // health check that expected icons and hover icons are present in the dom + cy.get('svg').should('have.length', 4) + + cy.percySnapshot('both cards unfocused') + + cy.get('@e2eTitle').focus() + cy.percySnapshot('card-1 focused') + + cy.get('@ctTitle').focus() + cy.percySnapshot('card-2 focused') + + // clicks work on card or button + cy.get('[data-cy="card"]').eq(0).click() + cy.get('[data-cy="card"]').eq(1).click() + cy.get('@e2eTitle').click() + cy.get('@ctTitle').click() + cy.get('@clickSpy').should('have.callCount', 4) + }) + + it('renders disabled state', () => { + const clickSpy = cy.spy().as('clickSpy') + + cy.mount(() => { + return ( +
+ +
+ ) + }) + + // button should be disabled + cy.contains('button', 'Disabled card') + .should('be.visible') + .and('be.disabled') + + // Asserting on pointer-events property because + // we can't actually click it + + cy.get('[data-cy="card"]') + .should('have.css', 'pointer-events', 'none') + + cy.get('@clickSpy').should('not.have.been.called') + + cy.percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/Card.vue b/packages/frontend-shared/src/components/Card.vue new file mode 100644 index 0000000000..181d5343b1 --- /dev/null +++ b/packages/frontend-shared/src/components/Card.vue @@ -0,0 +1,85 @@ + + + diff --git a/packages/frontend-shared/src/components/Checkbox.cy.tsx b/packages/frontend-shared/src/components/Checkbox.cy.tsx new file mode 100644 index 0000000000..10cef7933a --- /dev/null +++ b/packages/frontend-shared/src/components/Checkbox.cy.tsx @@ -0,0 +1,16 @@ +import { ref } from 'vue' +import Checkbox from './Checkbox.vue' + +describe('', () => { + it('renders', () => { + const value = ref(true) + + cy.mount(() => ( + Show the welcome guide when opening Cypress. + )) + }) +}) diff --git a/packages/frontend-shared/src/components/Checkbox.vue b/packages/frontend-shared/src/components/Checkbox.vue new file mode 100644 index 0000000000..cff4fe269a --- /dev/null +++ b/packages/frontend-shared/src/components/Checkbox.vue @@ -0,0 +1,56 @@ + + + diff --git a/packages/frontend-shared/src/components/CodeTag.cy.tsx b/packages/frontend-shared/src/components/CodeTag.cy.tsx new file mode 100644 index 0000000000..8bf722eaad --- /dev/null +++ b/packages/frontend-shared/src/components/CodeTag.cy.tsx @@ -0,0 +1,21 @@ +import CodeTag from './CodeTag.vue' + +describe('', () => { + it('looks good in code', () => { + cy.mount(() => (

+ Create a sample_spec.js file. +

)) + }) + + it('displays colored code', () => { + cy.mount(() => (

+ Create a sample_spec.js file. +

)) + }) + + it('displays colored code on a background', () => { + cy.mount(() => (

+ Create a sample_spec.js file. +

)) + }) +}) diff --git a/packages/frontend-shared/src/components/CodeTag.vue b/packages/frontend-shared/src/components/CodeTag.vue new file mode 100644 index 0000000000..17cd9cfe05 --- /dev/null +++ b/packages/frontend-shared/src/components/CodeTag.vue @@ -0,0 +1,21 @@ + + diff --git a/packages/frontend-shared/src/components/Collapsible.cy.tsx b/packages/frontend-shared/src/components/Collapsible.cy.tsx new file mode 100644 index 0000000000..e285f4d230 --- /dev/null +++ b/packages/frontend-shared/src/components/Collapsible.cy.tsx @@ -0,0 +1,151 @@ +import Collapsible from './Collapsible.vue' +import faker from 'faker' + +const targetText = 'Target' +const contentText = 'Content' +const targetSelector = '[data-testid=target]' +const contentSelector = '[data-testid=content]' +const defaultTargetSlot = ({ open }) =>
{ targetText }
+const defaultSlots = { target: defaultTargetSlot } + +describe('', { viewportHeight: 450, viewportWidth: 350 }, () => { + describe('initiallyOpen', () => { + it('defaults to closed', () => { + cy.mount(() => (<> + +

{ contentText }

+
+ )).get(targetSelector).should('have.class', 'not-open') + }) + + it('can be set to open initially', () => { + cy.mount(() => (<> + +

{ contentText }

+
+ )).get(targetSelector).should('have.class', 'open') + }) + }) + + it('renders the target and content slots', () => { + cy.mount(() => (<> + +

{ contentText }

+
+ )) + .get(targetSelector) + .should('contain.text', targetText) + .click() + .click() + .get(contentSelector) + .should('contain.text', contentText) + }) + + it('does not render default slot if lazy', () => { + cy.mount(() => (<> + +

{ contentText }

+
+ )) + .get(targetSelector) + .should('contain.text', targetText) + .click() + .click() + .get(contentSelector) + .should('not.exist') + }) + + it('overflows properly', () => { + const overflowedContentSelector = '[data-testid=overflowed-content]' + + cy.mount(() => ( +
Large content
+

Out-of-bounds content

+
)) + .get(targetSelector).click() + .get(overflowedContentSelector) + .should('not.be.visible') + .parent() + .scrollTo('bottom') + .get(overflowedContentSelector) + .should('be.visible') + }) + + it('does not toggle when clicking on content', () => { + cy.mount(() => (<> + +

{ contentText }

+
+ )) + .get(targetSelector) + .click() + .get(contentSelector) + .click() + .get(targetSelector) + .should('have.class', 'open') + }) + + describe('slotProps', () => { + describe('toggle', () => { + it('passes the toggle slot prop to the default slot', () => { + cy.mount(() => ( ( +
+ Inner Content +
), + }} />)) + .get(targetSelector) + .click() + .get(contentSelector) + .should('have.class', 'open') + .click() + .should('not.have.class', 'open') + }) + }) + + describe('open', () => { + const slotPropsDefaultSlot = ({ open }) =>
Content is: { open ? 'open' : 'not-open' }
+ + const slotPropsSlots = { + target: defaultTargetSlot, + default: slotPropsDefaultSlot, + } + + it('passes the open slot props to the header and default slots', () => { + cy.mount(() => ()) + .get(contentSelector) + .should('have.class', 'not-open') + .get(targetSelector) + .should('have.class', 'not-open') + .click() + .get(targetSelector) + .should('have.class', 'open') + .get(contentSelector) + .should('have.class', 'open') + }) + }) + }) + + it('playground', () => { + const text = faker.lorem.paragraphs(5) + const bottomText = 'Bottom Text' + + const target = ({ open }) => (

Click here to open

) + + cy.mount(() => (
+ + +
+

+ Content Header +

+

{ text }

+

{ bottomText }

+
+
+
)) + }) +}) diff --git a/packages/frontend-shared/src/components/Collapsible.vue b/packages/frontend-shared/src/components/Collapsible.vue new file mode 100644 index 0000000000..2939a3c45a --- /dev/null +++ b/packages/frontend-shared/src/components/Collapsible.vue @@ -0,0 +1,58 @@ + + + diff --git a/packages/frontend-shared/src/components/CopyText.cy.tsx b/packages/frontend-shared/src/components/CopyText.cy.tsx new file mode 100644 index 0000000000..fe123d718e --- /dev/null +++ b/packages/frontend-shared/src/components/CopyText.cy.tsx @@ -0,0 +1,31 @@ +import CopyText from './CopyText.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', () => { + it('renders without overflow', { viewportWidth: 800, viewportHeight: 120 }, () => { + cy.mount(() => ( +
+ +
+ )) + + cy.contains('button', defaultMessages.clipboard.copy) + .should('be.visible') + .percySnapshot() + }) + + it('overflows nicely', { viewportWidth: 800, viewportHeight: 120 }, () => { + const text = 'yarn workspace @packages/frontend-shared cypress:run --record --key 123as4d56asda987das' + + cy.mount(() => ( +
+ +
+ )) + + cy.contains(text) + cy.contains('button', defaultMessages.clipboard.copy) + .should('be.visible') + .percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/CopyText.vue b/packages/frontend-shared/src/components/CopyText.vue new file mode 100644 index 0000000000..6f49b3a351 --- /dev/null +++ b/packages/frontend-shared/src/components/CopyText.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/packages/frontend-shared/src/components/Icon.cy.tsx b/packages/frontend-shared/src/components/Icon.cy.tsx new file mode 100644 index 0000000000..e748e323ad --- /dev/null +++ b/packages/frontend-shared/src/components/Icon.cy.tsx @@ -0,0 +1,47 @@ +import Icon from './Icon.vue' +import IconCoffee from '~icons/mdi/coffee' +import IconHeart from '~icons/mdi/heart' + +describe('', () => { + it('handles an icon SVG', () => { + cy.mount(() => ( +
+ +
+ )).get('svg').should('be.visible') + }) + + it('playground', () => { + const textSizes = [ + 'xs', + 'sm', + 'md', + 'lg', + 'xl', + '2xl', + '3xl', + '6xl', + ] + + const colors = [ + 'rose', + 'red', + 'orange', + 'amber', + 'emerald', + 'indigo', + 'fuchsia', + 'pink', + ] + + cy.mount(() => (
+

Icon Sizes

+ { textSizes.map((size, i) => ( + + {size } + )) + } +
+ )) + }) +}) diff --git a/packages/frontend-shared/src/components/Icon.vue b/packages/frontend-shared/src/components/Icon.vue new file mode 100644 index 0000000000..2d3871d7f5 --- /dev/null +++ b/packages/frontend-shared/src/components/Icon.vue @@ -0,0 +1,26 @@ + + + + diff --git a/packages/frontend-shared/src/components/InlineCodeFragment.cy.tsx b/packages/frontend-shared/src/components/InlineCodeFragment.cy.tsx new file mode 100644 index 0000000000..f51be1eeec --- /dev/null +++ b/packages/frontend-shared/src/components/InlineCodeFragment.cy.tsx @@ -0,0 +1,11 @@ +import InlineCodeFragment from './InlineCodeFragment.vue' + +describe('', () => { + it('renders fragment', () => { + cy.mount(() => I am code) + + cy.contains('I am code') + .should('be.visible') + .percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/InlineCodeFragment.vue b/packages/frontend-shared/src/components/InlineCodeFragment.vue new file mode 100644 index 0000000000..4f9461f3ff --- /dev/null +++ b/packages/frontend-shared/src/components/InlineCodeFragment.vue @@ -0,0 +1,24 @@ + + diff --git a/packages/frontend-shared/src/components/Input.cy.tsx b/packages/frontend-shared/src/components/Input.cy.tsx new file mode 100644 index 0000000000..75f258c886 --- /dev/null +++ b/packages/frontend-shared/src/components/Input.cy.tsx @@ -0,0 +1,38 @@ +import Input from './Input.vue' +import { ref } from 'vue' +import CoffeeIcon from '~icons/mdi/coffee' +import LoadingIcon from '~icons/mdi/loading' + +describe('', { viewportWidth: 400, viewportHeight: 80 }, () => { + it('binds to v-model', () => { + const value = ref('') + const textToType = 'My wonderful input text' + + // @ts-ignore = vModel is v-model in vue + cy.mount(() => ) + cy.get('input').type(textToType, { delay: 0 }) + + cy.should(() => { + expect(value.value).to.equal(textToType) + }) + + cy.percySnapshot('without icons') + }) + + it('renders icons', () => { + const value = ref('Coffee Loading') + + cy.mount(() => ( + + )) + + cy.findAllByLabelText('status').should('have.value', 'Coffee Loading') + cy.percySnapshot('with icons') + }) +}) diff --git a/packages/frontend-shared/src/components/Input.vue b/packages/frontend-shared/src/components/Input.vue new file mode 100644 index 0000000000..4ba7c4647e --- /dev/null +++ b/packages/frontend-shared/src/components/Input.vue @@ -0,0 +1,122 @@ + + + + + + + diff --git a/packages/frontend-shared/src/components/ListRowHeader.cy.tsx b/packages/frontend-shared/src/components/ListRowHeader.cy.tsx new file mode 100644 index 0000000000..80883a8610 --- /dev/null +++ b/packages/frontend-shared/src/components/ListRowHeader.cy.tsx @@ -0,0 +1,49 @@ +import ListRowHeader from './ListRowHeader.vue' +import faker from 'faker' +import FileChangesAdded from '~icons/cy/file-changes-added_x24.svg' + +const description = faker.hacker.phrase() +const header = faker.system.directoryPath() +const iconSelector = '[data-testid=file-added-icon]' +const listRowSelector = '[data-testid=list-row-header]' +const descriptionSelector = '[data-testid=list-row-description]' + +describe('', () => { + it('renders the icon slot', () => { + cy.mount(() => ( +
+ , + description: () =>

{ description }

, + header: () => <>{ header }, + }} + /> +
+ )).get(iconSelector) + .should('be.visible') + .get(descriptionSelector) + .should('contain.text', description) + }) + + it('renders a minimal example with an icon and description', () => { + cy.mount(() => ( +
+ } + description={description} + // @ts-ignore - doesn't know about vSlots + vSlots={{ + header: () => <>{ header }, + }} + /> +
+ )) + .get(listRowSelector) + .should('contain.text', description) + .and('contain.text', header) + .get(iconSelector) + .should('be.visible') + }) +}) diff --git a/packages/frontend-shared/src/components/ListRowHeader.vue b/packages/frontend-shared/src/components/ListRowHeader.vue new file mode 100644 index 0000000000..fdd881acdc --- /dev/null +++ b/packages/frontend-shared/src/components/ListRowHeader.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/frontend-shared/src/components/NoInternetConnection.cy.tsx b/packages/frontend-shared/src/components/NoInternetConnection.cy.tsx new file mode 100644 index 0000000000..0f754a45dc --- /dev/null +++ b/packages/frontend-shared/src/components/NoInternetConnection.cy.tsx @@ -0,0 +1,22 @@ +import NoInternetConnection from './NoInternetConnection.vue' + +import { defaultMessages } from '@cy/i18n' + +describe('', () => { + it('renders expected contents', { viewportHeight: 300, viewportWidth: 300 }, () => { + cy.log('Mount with no slot content') + cy.mount(() => ) + cy.contains(defaultMessages.launchpadErrors.noInternet.header).should('be.visible') + + // icon should render but be hidden from screen readers + cy.get('[data-cy="no-connection-icon"]') + .should('be.visible') + .and('have.attr', 'aria-hidden') + + cy.log('Mount with slot content') + cy.mount(() => Extra Text ) + cy.contains('Extra Text').should('be.visible') + + cy.percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/NoInternetConnection.vue b/packages/frontend-shared/src/components/NoInternetConnection.vue new file mode 100644 index 0000000000..3e04f00506 --- /dev/null +++ b/packages/frontend-shared/src/components/NoInternetConnection.vue @@ -0,0 +1,22 @@ + + + diff --git a/packages/frontend-shared/src/components/NoResults.cy.tsx b/packages/frontend-shared/src/components/NoResults.cy.tsx new file mode 100644 index 0000000000..51366ef2ea --- /dev/null +++ b/packages/frontend-shared/src/components/NoResults.cy.tsx @@ -0,0 +1,29 @@ +import NoResults from './NoResults.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', () => { + it('renders if there is a search message', () => { + const testSearch = 'test search' + const clearSpy = cy.spy().as('clearSpy') + + cy.mount(() => ( +
+ )) + + cy.contains(testSearch).should('be.visible') + cy.contains(defaultMessages.noResults.defaultMessage).should('be.visible') + cy.contains('button', defaultMessages.noResults.clearSearch).should('be.visible') + .click() + .get('@clearSpy') + .should('have.been.calledOnce') + }) + + it('does not render if there is no search message', () => { + cy.mount(() => ( +
+ )) + + cy.contains(defaultMessages.noResults.defaultMessage).should('not.exist') + cy.contains('button', defaultMessages.noResults.clearSearch).should('not.exist') + }) +}) diff --git a/packages/frontend-shared/src/components/NoResults.vue b/packages/frontend-shared/src/components/NoResults.vue new file mode 100644 index 0000000000..b6e94c9e4f --- /dev/null +++ b/packages/frontend-shared/src/components/NoResults.vue @@ -0,0 +1,50 @@ + + + diff --git a/packages/frontend-shared/src/components/Radio.cy.tsx b/packages/frontend-shared/src/components/Radio.cy.tsx new file mode 100644 index 0000000000..cff7a39efd --- /dev/null +++ b/packages/frontend-shared/src/components/Radio.cy.tsx @@ -0,0 +1,51 @@ +import { ref } from 'vue' +import Radio from './Radio.vue' + +describe('', () => { + const options = [ + { + label: 'Private', + description: 'Only invited users can view recorded test results', + value: 'private', + }, + { + label: 'Public', + description: 'Everyone can view recorded test results', + value: 'public', + }, + ] + + it('should be updating values', () => { + const value = ref('private') + + cy.mount(() => (
+ value.value = val} + value={value.value} + name="projectAccess" + label="Project Access" + options={options} /> +
)) + + cy.findByText('Public').click().then(() => { + expect(value.value).to.eq('public') + }) + }) + + it('can use the option slot to customize rendering of options', () => { + const value = ref('private') + + cy.mount(() => (
+ value.value = val} + value={value.value} + name="projectAccess" + label="Project Access" + options={options} + v-slots={{ + option: ({ option }) =>
foo - {option.label}
, + }}/> +
)) + + cy.findByText('foo - Public').should('be.visible') + cy.findByText('foo - Private').should('be.visible') + }) +}) diff --git a/packages/frontend-shared/src/components/Radio.vue b/packages/frontend-shared/src/components/Radio.vue new file mode 100644 index 0000000000..b5ee10cf4e --- /dev/null +++ b/packages/frontend-shared/src/components/Radio.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/packages/frontend-shared/src/components/Select.cy.tsx b/packages/frontend-shared/src/components/Select.cy.tsx new file mode 100644 index 0000000000..93dbc1ebd8 --- /dev/null +++ b/packages/frontend-shared/src/components/Select.cy.tsx @@ -0,0 +1,210 @@ +import { defaultMessages } from '@cy/i18n' +import { h } from 'vue' + +// Subject Under Test +import Select from './Select.vue' +import IconHeart from '~icons/mdi/heart' + +const selectText = defaultMessages.components.select + +// Selectors +const optionsSelector = '[role=option]' +const inputSelector = '[aria-haspopup=true]' +const caretIconSelector = '[data-testid=icon-caret]' +const checkIconSelector = '[data-testid=icon-check]' + +// Helpers +const openSelect = () => cy.get(inputSelector).click() +const selectFirstOption = () => cy.get(optionsSelector).first().click().get(optionsSelector).first() + +// Fixtures +const defaultOptions = [ + { value: 'Blue', key: 'blue' }, + { value: 'Orange', key: 'orange' }, + { value: 'Fuchsia', key: 'fuchsia' }, +] + +// Mount wrapper to setup the component with default options +// and some root styles + +const mountSelect = (props: any = {}) => { + // v-model setup + let value = defaultOptions[0] + + // The width and padding need to be here so that + // a click on the body dismisses the options + return cy.mount(() => ( +
+ ', () => { + /** + * Using the Select Component within a template: + * + * + */ + + it('renders a list of options', () => { + mountSelect().then(openSelect).get(optionsSelector).should('be.visible') + cy.percySnapshot() + }) + + it('can open and choose an option', () => { + mountSelect().then(openSelect) + .then(selectFirstOption) + .then(($selectedOption) => { + cy.get(inputSelector).should('have.text', $selectedOption.text()) + }).get(optionsSelector).should('not.exist') + + cy.percySnapshot() + }) + + it('closes when clicking off of the options when open', () => { + mountSelect().then(openSelect) + .get(optionsSelector) + .should('be.visible') + .get('html').click(0, 0) + .get(optionsSelector).should('not.exist') + }) + + describe('#items', () => { + it('uses item keys and values for what to render', () => { + // Used for testing that "item-value" supports nested accessors + // e.g. 'profile.firstName' + const nestedOptions = [ + { profile: { firstName: 'Lachlan' }, id: 'ewiofjdew' }, + { profile: { firstName: 'Jess' }, id: '1i24u' }, + { profile: { firstName: 'Bart' }, id: 'ewopf' }, + ] + + mountSelect({ + options: nestedOptions, + modelValue: nestedOptions[0], + itemKey: 'id', + itemValue: 'profile.firstName', + }).then(openSelect) + .get(optionsSelector).first() + .should('have.text', nestedOptions[0].profile.firstName) + }) + }) + + describe('#icons', () => { + // TODO: Enable with completion of UNIFY-1375 + it.skip('marks the selected item with a check by default', () => { + mountSelect().then(openSelect) + .then(selectFirstOption) + .then(openSelect) + .get(optionsSelector).first() + .find(checkIconSelector).should('be.visible') + }) + + it('renders a caret by default', () => { + mountSelect().get(caretIconSelector).should('be.visible') + }) + }) + + describe('#placeholder', () => { + it('default placeholder when theres no value selected', () => { + mountSelect({ modelValue: undefined }) + .get(inputSelector) + .should('contain.text', selectText.placeholder) + }) + + it('custom placeholder when theres no value selected', () => { + mountSelect({ + placeholder: 'My placeholder', + modelValue: undefined, + }).get(inputSelector).should('contain.text', 'My placeholder') + }) + + it('does not render the placeholder after selecting an option', () => { + // The width and padding need to be here so that + // a click on the body dismisses the options + cy.mount({ + components: { Select }, + data () { + return { + model: undefined, + } + }, + render () { + return h(Select, { + modelValue: this.model, + 'onUpdate:modelValue': (value: any) => this.model = value, + options: defaultOptions, + placeholder: 'A placeholder', + }) + }, + }).then(() => { + cy.get(inputSelector) + .should('contain.text', 'A placeholder') + .then(openSelect) + .then(selectFirstOption) + .get(inputSelector) + .should('not.contain.text', 'A placeholder') + }) + }) + + it('does not render the placeholder when there is a value selected', () => { + mountSelect({ + placeholder: 'A placeholder', + modelValue: defaultOptions[0], + }).get(inputSelector).should('not.contain.text', 'A placeholder') + }) + }) + + describe('#slots', () => { + it('renders all of the slots', () => { + const vSlots = { + 'item-body': () => 'Item Body', + 'item-prefix': () => , + 'item-suffix': () => , + 'selected': () => 'Selected', + 'input-prefix': () => , + 'input-suffix': () => , + } + + mountSelect({ vSlots }) + + // The input and tis prefixes and suffixes should be visible + cy.findByText('Selected').should('be.visible') + .get(`[data-testid=input-prefix]`).should('be.visible') + .get(`[data-testid=input-suffix]`).should('be.visible') + + // The caret icon shouldn't exist because we overwrote it + .get(caretIconSelector).should('not.exist') + + // Open the select + .then(openSelect) + + // The options and their prefixes + suffixes should be visible + .get(optionsSelector).should('be.visible') + .get(`[data-testid=item-prefix]`).should('be.visible') + .get(`[data-testid=item-suffix]`).should('be.visible') + .percySnapshot() + + // Choose an option + .then(selectFirstOption) + + // The options list should be closed + .get(optionsSelector).should('not.exist') + .get(inputSelector).should('have.text', 'Selected') + .then(openSelect) + + // The check mark shouldn't exist because we overwrote it + .get(checkIconSelector).should('not.exist') + }) + }) +}) diff --git a/packages/frontend-shared/src/components/Select.vue b/packages/frontend-shared/src/components/Select.vue new file mode 100644 index 0000000000..1c365db645 --- /dev/null +++ b/packages/frontend-shared/src/components/Select.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/packages/frontend-shared/src/components/ShikiHighlight.cy.tsx b/packages/frontend-shared/src/components/ShikiHighlight.cy.tsx new file mode 100644 index 0000000000..121b291101 --- /dev/null +++ b/packages/frontend-shared/src/components/ShikiHighlight.cy.tsx @@ -0,0 +1,88 @@ +import ShikiHighlight, { initHighlighter } from './ShikiHighlight.vue' +import code from '../../windi.config?raw' + +const devServerCode = `const { defineConfig } = require('cypress') +const { devServer } = require('@cypress/vite-dev-server') + +module.exports = defineConfig({ + component: { + devServer, + devServerConfig: { + entryHtmlFile: 'cypress/component/support/entry.html' + }, + }, +})` + +describe('', { viewportWidth: 800, viewportHeight: 500 }, () => { + beforeEach(async () => { + initHighlighter() + }) + + it('playground', () => { + cy.mount(() => (
+ +
)) + + cy.contains(devServerCode).should('be.visible') + cy.percySnapshot() + }) + + it('trims whitespace to show the correct number of lines', { viewportWidth: 500, viewportHeight: 500 }, () => { + const line = `console.log('my string')` + const numLines = 15 + + // Whitespace + // eslint-disable-next-line + const code = ` + + + ${Array.from(Array(numLines).keys()).map(() => line).join('\n')} + + + ` + + cy.mount(() => (
+ +
)) + .get('.line') + .should('have.length', numLines) + + cy.percySnapshot() + }) + + // TODO: (UNIFY-921) unskip when `wrap` prop is needed and working (currently used nowhere) + it.skip('wraps long code without line numbers', { viewportWidth: 900, viewportHeight: 500 }, () => { + cy.mount(() =>
) + cy.get('.shiki').should('be.visible') + }) + + // TODO: (UNIFY-921) unskip when `wrap` prop is needed and working (currently used nowhere) + it.skip('wraps long code with line numbers', () => { + cy.mount(() =>
) + cy.get('.shiki').should('be.visible') + }) + + it('render the code without arguments', () => { + cy.mount(() =>
) + cy.get('.shiki').should('be.visible') + cy.percySnapshot() + }) + + it('display inline and remove some of the padding when "inline"', { viewportWidth: 300, viewportHeight: 100 }, () => { + cy.mount(() => ) + cy.get('.shiki').should('be.visible') + cy.percySnapshot() + }) + + it('show line numbers when the prop is passed', () => { + cy.mount(() =>
) + cy.get('.shiki').should('be.visible') + cy.percySnapshot() + }) + + it('show line numbers with initial line when the prop is passed', () => { + cy.mount(() =>
) + cy.get('.shiki').should('be.visible') + cy.percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/ShikiHighlight.vue b/packages/frontend-shared/src/components/ShikiHighlight.vue new file mode 100644 index 0000000000..668bf612f1 --- /dev/null +++ b/packages/frontend-shared/src/components/ShikiHighlight.vue @@ -0,0 +1,234 @@ + + + + + + + + + + + diff --git a/packages/frontend-shared/src/components/Spinner.cy.tsx b/packages/frontend-shared/src/components/Spinner.cy.tsx new file mode 100644 index 0000000000..841cadbff5 --- /dev/null +++ b/packages/frontend-shared/src/components/Spinner.cy.tsx @@ -0,0 +1,11 @@ +import Spinner from './Spinner.vue' + +describe('', { viewportHeight: 200, viewportWidth: 200 }, () => { + it('renders', () => { + cy.mount(() => ( + + )) + + cy.percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/Spinner.vue b/packages/frontend-shared/src/components/Spinner.vue new file mode 100644 index 0000000000..c8ec6c2df0 --- /dev/null +++ b/packages/frontend-shared/src/components/Spinner.vue @@ -0,0 +1,68 @@ + + + diff --git a/packages/frontend-shared/src/components/StandardModal.cy.tsx b/packages/frontend-shared/src/components/StandardModal.cy.tsx new file mode 100644 index 0000000000..13b7317c1e --- /dev/null +++ b/packages/frontend-shared/src/components/StandardModal.cy.tsx @@ -0,0 +1,131 @@ +import StandardModal from './StandardModal.vue' +import { defaultMessages } from '@cy/i18n' +import { ref } from 'vue' + +const title = 'Test Title' +const body = 'Test body text' + +describe('', { viewportWidth: 800, viewportHeight: 400 }, () => { + describe('default render and variations', () => { + it('renders expected content in open state', () => { + const isOpen = ref(true) + + cy.mount({body} + ) + + cy.contains('a', defaultMessages.links.needHelp) + .should('be.visible') + .and('have.attr', 'href', 'https://on.cypress.io') + + cy.findByLabelText(defaultMessages.actions.close, { + selector: 'button', + }) + .should('be.visible') + .and('not.be.disabled') + + cy.contains('h2', title).should('be.visible') + cy.contains(body).should('be.visible') + + cy.percySnapshot() + }) + + it('bare variant renders without padding in body', () => { + cy.mount({body} + ) + + cy.contains(title).should('be.visible') + + cy.percySnapshot() + }) + + it('optional classes pass through to the modal root element', () => { + const testClass = 'text-pink-400' + + cy.mount({body} + ) + + cy.contains(title).should('be.visible') + .closest(`[data-cy=standard-modal].${testClass}`) + .should('exist') + + cy.percySnapshot() + }) + }) + + describe('mouse and keyboard behavior', () => { + beforeEach(() => { + const isOpen = ref(true) + const updateSpy = cy.spy().as('updateSpy') + + const props = { + 'onUpdate:modelValue': (value) => { + updateSpy(value) + isOpen.value = value + }, + } + + cy.mount({body} + ) + + cy.findByLabelText(defaultMessages.actions.close, { + selector: 'button', + }).as('closeButton') + }) + + it('closes when Close button is clicked', () => { + cy.get('@closeButton') + .click() + .then(() => { + cy.get('@updateSpy').should('have.been.calledOnceWith', false) + }) + }) + + it('closes with Space key on close button', () => { + cy.get('@closeButton').focus().realPress('Space') + cy.get('@updateSpy').should('have.been.calledOnceWith', false) + }) + + it('closes with enter key on close button', () => { + cy.get('@closeButton').focus().realPress('Enter') + cy.get('@updateSpy').should('have.been.calledOnceWith', false) + }) + + it('closes with Esc key', () => { + cy.get('body').type('{esc}') + cy.get('@updateSpy').should('have.been.calledOnceWith', false) + }) + + it('closes with click-outside', () => { + cy.get('body').click() + cy.get('@updateSpy').should('have.been.calledOnceWith', false) + }) + + it('does not close w/ click-outside when viewport is xs', { viewportWidth: 400 }, () => { + cy.get('body').click() + cy.get('@updateSpy').should('not.have.been.called') + }) + + it(`doesn't close with click inside`, () => { + cy.contains(title).click() + cy.get('@updateSpy').should('not.have.been.called') + }) + }) +}) diff --git a/packages/frontend-shared/src/components/StandardModal.vue b/packages/frontend-shared/src/components/StandardModal.vue new file mode 100644 index 0000000000..3514acb1e5 --- /dev/null +++ b/packages/frontend-shared/src/components/StandardModal.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/packages/frontend-shared/src/components/StandardModalBody.vue b/packages/frontend-shared/src/components/StandardModalBody.vue new file mode 100644 index 0000000000..18d967f3cc --- /dev/null +++ b/packages/frontend-shared/src/components/StandardModalBody.vue @@ -0,0 +1,12 @@ + + + diff --git a/packages/frontend-shared/src/components/StandardModalFooter.vue b/packages/frontend-shared/src/components/StandardModalFooter.vue new file mode 100644 index 0000000000..015230d9b2 --- /dev/null +++ b/packages/frontend-shared/src/components/StandardModalFooter.vue @@ -0,0 +1,5 @@ + diff --git a/packages/frontend-shared/src/components/StandardModalHeader.vue b/packages/frontend-shared/src/components/StandardModalHeader.vue new file mode 100644 index 0000000000..9ba25e5442 --- /dev/null +++ b/packages/frontend-shared/src/components/StandardModalHeader.vue @@ -0,0 +1,46 @@ + + + diff --git a/packages/frontend-shared/src/components/StatusIndicator.cy.tsx b/packages/frontend-shared/src/components/StatusIndicator.cy.tsx new file mode 100644 index 0000000000..98055147a6 --- /dev/null +++ b/packages/frontend-shared/src/components/StatusIndicator.cy.tsx @@ -0,0 +1,41 @@ +import _ from 'lodash' +import type { StatusIndicatorType } from './StatusIndicator.vue' +import StatusIndicator from './StatusIndicator.vue' + +const types = { + success: `Sweet`, + error: `Ahhh!`, + warning: `Hmmmm...`, + disabled: `Nah`, +} as const + +const renderStatusIndicator = (text: string, status: StatusIndicatorType) => { + return ( + + {status} + + {text} + + + ) +} + +describe('', () => { + it('renders all states', () => { + cy.mount(() => ( +
+

Status Indicators

+
+ {Object.entries(types).map(([type, text]) => renderStatusIndicator(text, type as StatusIndicatorType))} +
+
+ )) + + _.forEach(types, (text) => { + cy.findByText(text).should('be.visible') + }) + }) +}) diff --git a/packages/frontend-shared/src/components/StatusIndicator.vue b/packages/frontend-shared/src/components/StatusIndicator.vue new file mode 100644 index 0000000000..1e5d3f9299 --- /dev/null +++ b/packages/frontend-shared/src/components/StatusIndicator.vue @@ -0,0 +1,31 @@ + + + diff --git a/packages/frontend-shared/src/components/Switch.cy.tsx b/packages/frontend-shared/src/components/Switch.cy.tsx new file mode 100644 index 0000000000..f832fe8461 --- /dev/null +++ b/packages/frontend-shared/src/components/Switch.cy.tsx @@ -0,0 +1,27 @@ +import { ref } from 'vue' +import Switch from './Switch.vue' + +describe('', () => { + it('playground', { viewportWidth: 80, viewportHeight: 60 }, () => { + const valueRef = ref(false) + + cy.mount(() => ( +
+ + (valueRef.value = newVal)} + name="test-switch" + /> +
+ )) + + cy.get('button') + .click() + .then(() => { + expect(valueRef.value).to.be.true + }) + }) +}) diff --git a/packages/frontend-shared/src/components/Switch.vue b/packages/frontend-shared/src/components/Switch.vue new file mode 100644 index 0000000000..7d8f99e988 --- /dev/null +++ b/packages/frontend-shared/src/components/Switch.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/frontend-shared/src/components/TerminalPrompt.cy.tsx b/packages/frontend-shared/src/components/TerminalPrompt.cy.tsx new file mode 100644 index 0000000000..c7948b6343 --- /dev/null +++ b/packages/frontend-shared/src/components/TerminalPrompt.cy.tsx @@ -0,0 +1,33 @@ +import TerminalPrompt from './TerminalPrompt.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', () => { + it('renders without overflow', { viewportWidth: 800, viewportHeight: 120 }, () => { + cy.mount(() => ( +
+ +
+ )) + + cy.contains('button', defaultMessages.clipboard.copy) + .should('be.visible') + .percySnapshot() + }) + + it('overflows nicely', { viewportWidth: 800, viewportHeight: 120 }, () => { + const command = 'yarn workspace @packages/frontend-shared cypress:run --record --key 123as4d56asda987das' + const projectFolderName = 'design-system' + + cy.mount(() => ( +
+ +
+ )) + + cy.contains(command) + cy.contains(projectFolderName) + cy.contains('button', defaultMessages.clipboard.copy) + .should('be.visible') + .percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/components/TerminalPrompt.vue b/packages/frontend-shared/src/components/TerminalPrompt.vue new file mode 100644 index 0000000000..aec6e638e8 --- /dev/null +++ b/packages/frontend-shared/src/components/TerminalPrompt.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/packages/frontend-shared/src/components/transitions/TransitionQuickFade.vue b/packages/frontend-shared/src/components/transitions/TransitionQuickFade.vue new file mode 100644 index 0000000000..9877e440ea --- /dev/null +++ b/packages/frontend-shared/src/components/transitions/TransitionQuickFade.vue @@ -0,0 +1,12 @@ + diff --git a/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.cy.tsx b/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.cy.tsx new file mode 100644 index 0000000000..24e516a588 --- /dev/null +++ b/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.cy.tsx @@ -0,0 +1,7 @@ +import UseCollapsibleTreeExample from './UseCollapsibleTreeExample.vue' + +describe('', () => { + it('renders', () => { + cy.mount(() => ) + }) +}) diff --git a/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.vue b/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.vue new file mode 100644 index 0000000000..08d4c9c24e --- /dev/null +++ b/packages/frontend-shared/src/composables/examples/UseCollapsibleTreeExample.vue @@ -0,0 +1,70 @@ + + + diff --git a/packages/frontend-shared/src/composables/examples/UseMarkdownExample.cy.tsx b/packages/frontend-shared/src/composables/examples/UseMarkdownExample.cy.tsx new file mode 100644 index 0000000000..b1e11319c4 --- /dev/null +++ b/packages/frontend-shared/src/composables/examples/UseMarkdownExample.cy.tsx @@ -0,0 +1,67 @@ +import { ExternalLink_OpenExternalDocument } from '../../generated/graphql' +import UseMarkdownExample from './UseMarkdownExample.vue' + +describe('useMarkdown', () => { + it('renders styled markdown', () => { + const text = ` +# Heading 1 +## Heading 2 +### Heading 3 +#### Heading 4 +##### Heading 5 +###### Heading 6 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec justo feugiat, auctor nunc ac, volutpat arcu. Suspendisse faucibus aliquam ante, sit amet iaculis dolor posuere et. In ut placerat leo. + +Has **bold text** and *italic text* and \`code\`. + +- list 1 +- list 2 +- list 3 + +1. numbered list 1 +2. numbered list 2 +3. numbered list 3 + +[a link](https://example.com) + +\`\`\` +const heres = { + some: 'code', +} +\`\`\` + +[Simple Link](www.test.com) +[\`Code Link\`](www.code.com) + + + ` + + cy.mount() + + cy.get('ul').should('have.class', 'list-disc') + cy.get('code').first().should('have.class', 'bg-pink-200').and('have.class', 'text-pink-600') + + const openExternalStub = cy.stub() + + cy.stubMutationResolver(ExternalLink_OpenExternalDocument, (defineResult, { url }) => { + openExternalStub(url) + + return defineResult({ + openExternal: true, + }) + }) + + cy.contains('a', 'Simple Link').click() + cy.wrap(openExternalStub).should('have.been.calledWith', 'www.test.com') + + cy.contains('a', 'Code Link').within(() => { + cy.get('code').click() + }) + + cy.wrap(openExternalStub).should('have.been.calledWith', 'www.code.com') + }) +}) diff --git a/packages/frontend-shared/src/composables/examples/UseMarkdownExample.vue b/packages/frontend-shared/src/composables/examples/UseMarkdownExample.vue new file mode 100644 index 0000000000..19fc67cf98 --- /dev/null +++ b/packages/frontend-shared/src/composables/examples/UseMarkdownExample.vue @@ -0,0 +1,21 @@ + + + diff --git a/packages/frontend-shared/src/composables/index.ts b/packages/frontend-shared/src/composables/index.ts new file mode 100644 index 0000000000..bc46d5394d --- /dev/null +++ b/packages/frontend-shared/src/composables/index.ts @@ -0,0 +1,18 @@ +import { computed } from 'vue' + +/** + * This snippet comes from Thorsten Lรผnborg and is explained in this blog post https://www.vuemastery.com/blog/vue-3-data-down-events-up/ + * @example const localValue = useModelWrapper(props, emit, 'modelValue') + */ +export function useModelWrapper ( + props: T, + emit: (event: N, ...args: any[]) => void, + name = 'modelValue', +) { + return computed({ + get: () => props[name], + set: (value: any) => { + emit(`update:${name}` as any, value) + }, + }) +} diff --git a/packages/frontend-shared/src/composables/useCollapsibleTree.ts b/packages/frontend-shared/src/composables/useCollapsibleTree.ts new file mode 100644 index 0000000000..3003396c50 --- /dev/null +++ b/packages/frontend-shared/src/composables/useCollapsibleTree.ts @@ -0,0 +1,114 @@ +import type { ComputedRef, Ref } from 'vue' +import { computed } from 'vue' +import { useToggle } from '@vueuse/core' + +export type RawNode = { + name: string + children: RawNode[] +} + +export type UseCollapsibleTreeNode > = { + // control open/close state + hidden: ComputedRef + expanded: Ref + toggle: () => void + + // Depth of a particular node -- 1 indexed + depth: number + + parent?: UseCollapsibleTreeNode + children: UseCollapsibleTreeNode[] +} & { [K in keyof T]: T[K]} + +export interface UseCollapsibleTreeOptions { + expandInitially?: boolean + dropRoot?: boolean +} + +function collectRoots> (node: UseCollapsibleTreeNode | null, acc: UseCollapsibleTreeNode[] = []) { + if (!node || !node.parent) { + return acc + } + + acc.push(node) + + collectRoots(node.parent, acc) + + return acc +} + +export const useCollapsibleTreeNode = >(rawNode: T, options: UseCollapsibleTreeOptions, depth: number, parent: UseCollapsibleTreeNode | null): UseCollapsibleTreeNode => { + const treeNode = rawNode as UseCollapsibleTreeNode + const roots = parent ? collectRoots(parent) : [] + const [expanded, toggle] = useToggle(!!options.expandInitially) + const hidden = computed(() => { + return !!roots.find((r) => r.expanded.value === false) + }) + + return { + ...treeNode, + depth, + parent, + hidden, + expanded, + toggle, + } +} + +function buildTree> (rawNode: T, options: UseCollapsibleTreeOptions, acc: UseCollapsibleTreeNode[] = [], depth = 1, parent: UseCollapsibleTreeNode | null = null) { + const node = useCollapsibleTreeNode(rawNode, options, depth, parent) + + acc.push(node) + + if (node.children?.length) { + for (const child of node.children) { + buildTree(child, options, acc, depth + 1, node) + } + } + + return acc +} + +function sortTree> (tree: T) { + if (tree.children.length > 0) { + tree.children = tree.children.sort((a, b) => { + if (a.children.length === 0 && b.children.length === 0) { + return a.name > b.name ? 1 : -1 + } + + if (a.children.length === 0) { + return 1 + } + + if (b.children.length === 0) { + return -1 + } + + return a.name > b.name ? 1 : -1 + }) + + tree.children.forEach(sortTree) + } +} + +export function useCollapsibleTree > (tree: T, options: UseCollapsibleTreeOptions = {}) { + options.expandInitially = options.expandInitially || true + sortTree(tree) + const collapsibleTree = buildTree(tree, options) + + collapsibleTree.sort((a, b) => { + if (a.parent === b.parent) { + if (a.children.length && !b.children.length) { + return -1 + } + + return 0 + } + + return 0 + }) + + return { + tree: options.dropRoot ? collapsibleTree.slice(1) : collapsibleTree, + } +} diff --git a/packages/frontend-shared/src/composables/useListNavigation.ts b/packages/frontend-shared/src/composables/useListNavigation.ts new file mode 100644 index 0000000000..4fef406f5a --- /dev/null +++ b/packages/frontend-shared/src/composables/useListNavigation.ts @@ -0,0 +1,52 @@ +import { onKeyStroke } from '@vueuse/core' +import { ref, onBeforeUpdate } from 'vue' + +export const useListNavigation = (rootEl) => { + const selectedItem = ref(0) + const itemRefs = ref([]) as any + const setItemRef = (el) => { + if (el) { + itemRefs.value.push(el) + } + } + + onBeforeUpdate(() => { + itemRefs.value = [] + }) + + const goToItem = (direction: 'next' | 'previous', event) => { + event.preventDefault() + if (direction === 'next') { + if (selectedItem.value + 1 >= itemRefs.value.length) { + selectedItem.value = 0 + } else { + selectedItem.value++ + } + } else { + if (selectedItem.value <= 0) { + selectedItem.value = itemRefs.value.length - 1 + } else { + selectedItem.value-- + } + } + + itemRefs.value[selectedItem.value]?.focus({ preventScroll: true }) + itemRefs.value[selectedItem.value]?.scrollIntoView({ block: 'nearest' }) + } + + onKeyStroke('ArrowDown', (event: KeyboardEvent) => { + goToItem('next', event) + }, { target: rootEl }) + + onKeyStroke('ArrowUp', (event) => { + goToItem('previous', event) + }, { target: rootEl }) + + return { + selectedItem, + rowProps: { + ref: setItemRef, + tabindex: '-1', + }, + } +} diff --git a/packages/frontend-shared/src/composables/useMarkdown.ts b/packages/frontend-shared/src/composables/useMarkdown.ts new file mode 100644 index 0000000000..5c7ea7eec2 --- /dev/null +++ b/packages/frontend-shared/src/composables/useMarkdown.ts @@ -0,0 +1,125 @@ +/** + * Add styling for markdown components here. + * NOTICE: For Syntax Highlighting, please use the ShikiHighlight component. + * We could eventually use Shiki as a Markdown plugin, but I don't want to get into it right now. + */ +import type { Ref } from 'vue' +import { computed, unref } from 'vue' +import MarkdownIt from 'markdown-it' +import MarkdownItClass from '@toycode/markdown-it-class' +import { useEventListener, whenever } from '@vueuse/core' +import type { MaybeRef } from '@vueuse/core' +import { useExternalLink } from '../gql-components/useExternalLink' +import { mapValues, isArray, flatten } from 'lodash' + +export interface UseMarkdownOptions { + openExternal?: boolean + classes?: { + overwrite?: boolean + h1?: string[] | string + h2?: string[] | string + h3?: string[] | string + h4?: string[] | string + h5?: string[] | string + h6?: string[] | string + pre?: string[] | string + p?: string[] | string + a?: string[] | string + ul?: string[] | string + li?: string[] | string + ol?: string[] | string + code?: string[] | string + } +} + +const defaultClasses = { + h1: ['font-medium', 'text-4xl', 'mb-6'], + h2: ['font-medium', 'text-3xl', 'mb-5'], + h3: ['font-medium', 'text-2xl', 'mb-4'], + h4: ['font-medium', 'text-1xl', 'mb-3'], + h5: ['font-medium', 'text-sm', 'mb-3'], + h6: ['font-medium', 'text-xs', 'mb-3'], + p: ['my-3 first:mt-0 text-sm mb-4'], + pre: ['rounded p-3 bg-white mb-2'], + code: [`font-medium rounded text-sm px-4px py-2px bg-red-100`], + a: ['text-blue-500', 'hover:underline text-sm'], + ul: ['list-disc pl-6 my-3 text-sm'], + ol: ['list-decimal pl-6 my-3 text-sm'], +} + +const buildClasses = (options) => { + // --- Normalize + Merge the classes --- + // Array notation supports a single class or space-delimited classes. + // Input: `['bg-pink text-pink-500', 'text-medium']` + // Output: `[...defaults, 'bg-pink', 'text-pink-500', 'text-medium']` + + // String notation is also supported and split by empty space + // Input: `'bg-pink text-pink-500'` + // Output: `[...defaults, 'bg-pink', text-pink-500']` + + const _classes = defaultClasses // Constant above + + const buildFlat = (value) => { + if (isArray(value)) { + return flatten(value).map((arrValue) => arrValue.split(' ')) + } + + return value?.split(' ') ?? [] + } + + // Transform each value from defaultClasses and merge it with the user + // input classes. + if (options.classes) { + return mapValues(_classes, (defaultValue, key) => { + const inputClasses = buildFlat(options.classes[key]) + + if (options.classes.overwrite) return flatten([...inputClasses]) + + return flatten([...buildFlat(defaultValue), ...inputClasses]) + }) + } + + return _classes +} + +export const useMarkdown = (target: Ref, text: MaybeRef, options: UseMarkdownOptions = {}) => { + options.openExternal = options.openExternal || true + + const classes = buildClasses(options) + + const md = MarkdownIt({ + html: true, + linkify: true, + highlight (str) { + return `
${str}
` + }, + }) + + md.use(MarkdownItClass, classes) + + if (options.openExternal) { + const open = useExternalLink() + + whenever(target, () => { + useEventListener(target, 'click', (e: MouseEvent) => { + const link = (e.target as HTMLElement).closest('a[href]') + + if (!link) { + return + } + + e.preventDefault() + + const url = link.getAttribute('href') + + if (url) { + open(url) + } + }) + }) + } + + return { + markdown: computed(() => md.render(unref(text), { sanitize: true })), + } +} diff --git a/packages/frontend-shared/src/composables/useVirtualList.ts b/packages/frontend-shared/src/composables/useVirtualList.ts new file mode 100644 index 0000000000..47d7735ada --- /dev/null +++ b/packages/frontend-shared/src/composables/useVirtualList.ts @@ -0,0 +1,178 @@ +import type { Ref, CSSProperties } from 'vue' +import { watch, ref, computed, shallowRef } from 'vue' +import type { MaybeRef } from '@vueuse/core' +import { useElementSize } from '@vueuse/core' +import { isEqual } from 'lodash' + +export type UseVirtualListApi = ReturnType['api'] + +export interface UseVirtualListOptions { + /** + * item height, accept a pixel value or a function that returns the height + * + * @default 0 + */ + itemHeight: number | ((index: number) => number) + /** + * the extra buffer items outside of the view area + * + * @default 5 + */ + overscan?: number +} + +export type UseVirtualListItem = { + data: T + index: number +} + +export function useVirtualList (list: MaybeRef, options: UseVirtualListOptions) { + const containerRef: Ref = ref() + + const size = useElementSize(containerRef) + + const currentList: Ref[]> = ref([]) + const source = shallowRef(list) + + const state: Ref = ref({ start: 0, end: 10 }) + const { itemHeight, overscan = 5 } = options + + const getViewCapacity = (containerHeight: number) => { + if (typeof itemHeight === 'number') { + return Math.ceil(containerHeight / itemHeight) + } + + const { start = 0 } = state.value + let sum = 0 + let capacity = 0 + + for (let i = start; i < source.value.length; i++) { + const height = (itemHeight as (index: number) => number)(i) + + sum += height + if (sum >= containerHeight) { + capacity = i + break + } + } + + return capacity - start + } + + const getOffset = (scrollTop: number) => { + if (typeof itemHeight === 'number') { + return Math.floor(scrollTop / itemHeight) + 1 + } + + let sum = 0 + let offset = 0 + + for (let i = 0; i < source.value.length; i++) { + const height = (itemHeight as (index: number) => number)(i) + + sum += height + if (sum >= scrollTop) { + offset = i + break + } + } + + return offset + 1 + } + + const calculateRange = () => { + const element = containerRef.value + + if (element) { + const offset = getOffset(element.scrollTop) + const viewCapacity = getViewCapacity(element.clientHeight) + + const from = offset - overscan + const to = offset + viewCapacity + overscan + + state.value = { + start: from < 0 ? 0 : from, + end: to > source.value.length + ? source.value.length + : to, + } + + currentList.value = source.value + .slice(state.value.start, state.value.end) + .map((ele, index) => { + return { + data: ele, + index: index + state.value.start, + } + }) + } + } + + watch([size.height, list], (newVal, oldVal) => { + if (!isEqual(newVal, oldVal)) { + calculateRange() + } + }) + + const totalHeight = computed(() => { + if (typeof itemHeight === 'number') { + return source.value.length * itemHeight + } + + return source.value.reduce((sum, _, index) => sum + itemHeight(index), 0) + }) + + const getDistanceTop = (index: number) => { + if (typeof itemHeight === 'number') { + const height = index * itemHeight + + return height + } + + const height = source.value + .slice(0, index) + .reduce((sum, _, i) => sum + itemHeight(i), 0) + + return height + } + + const scrollTo = (index: number) => { + if (containerRef.value) { + containerRef.value.scrollTop = getDistanceTop(index) + calculateRange() + } + } + + const offsetTop = computed(() => getDistanceTop(state.value.start)) + const wrapperProps = computed(() => { + return { + style: { + width: '100%', + height: `${totalHeight.value - offsetTop.value}px`, + marginTop: `${offsetTop.value}px`, + }, + } + }) + + const containerStyle: CSSProperties = { overflowY: 'auto' } + + return { + list: currentList, + scrollTo, + containerProps: { + ref: containerRef, + onScroll: () => { + calculateRange() + }, + style: containerStyle, + }, + wrapperProps, + api: { + containerRef, + getOffset, + getViewCapacity, + source, + scrollTo, + }, + } +} diff --git a/packages/frontend-shared/src/composables/useVirtualListNavigation.ts b/packages/frontend-shared/src/composables/useVirtualListNavigation.ts new file mode 100644 index 0000000000..1b514c69aa --- /dev/null +++ b/packages/frontend-shared/src/composables/useVirtualListNavigation.ts @@ -0,0 +1,97 @@ +import { onBeforeUpdate, onUpdated, ref, unref } from 'vue' +import { onKeyStroke } from '@vueuse/core' +import type { UseVirtualListApi } from './useVirtualList' + +const focusEl = (itemRefs, activeItem) => { + const idx = unref(activeItem) + const el = itemRefs.value[idx]?.$el ?? itemRefs.value[idx] + + if (typeof el?.focus === 'function') { + el.focus({ preventScroll: true }) + } +} + +export function useVirtualListNavigation ({ + containerRef, + getOffset, + getViewCapacity, + source, + scrollTo, +}: UseVirtualListApi) { + const activeItem = ref(null) + const itemRefs = ref<{[key: number]: any}>({}) + const setItemRef = (el, index: number) => { + if (el) { + itemRefs.value[index] = el + } + } + + onBeforeUpdate(() => { + itemRefs.value = {} + }) + + onUpdated(() => { + focusEl(itemRefs, activeItem) + }) + + onKeyStroke('ArrowDown', (event: KeyboardEvent) => { + event.preventDefault() + const element = containerRef.value + + if (element) { + activeItem.value = activeItem.value ?? 0 + if ((activeItem.value + 1) === source.value.length) { + activeItem.value = 0 + scrollTo(activeItem.value) + + return + } + + activeItem.value++ + + const offset = getOffset(element.scrollTop) + const viewCapacity = getViewCapacity(element.clientHeight) + + const fromIdx = offset - 1 + const toIdx = fromIdx + (viewCapacity - 1) + + if (activeItem.value >= toIdx) { + scrollTo(fromIdx + 1) + } else { + focusEl(itemRefs, activeItem) + } + } + }, { target: containerRef }) + + onKeyStroke('ArrowUp', (event) => { + event.preventDefault() + const element = containerRef.value + + if (element) { + activeItem.value = activeItem.value ?? 0 + if (activeItem.value === 0) { + activeItem.value = source.value.length - 1 + scrollTo(activeItem.value) + + return + } + + activeItem.value-- + + const offset = getOffset(element.scrollTop) + + const fromIndex = offset - 1 + + if (activeItem.value < fromIndex) { + scrollTo(fromIndex - 1) + } else { + focusEl(itemRefs, activeItem) + } + } + }, { target: containerRef }) + + return { + activeItem, + setItemRef, + } +} diff --git a/packages/frontend-shared/src/gql-components/Auth.vue b/packages/frontend-shared/src/gql-components/Auth.vue new file mode 100644 index 0000000000..0f858b1a8c --- /dev/null +++ b/packages/frontend-shared/src/gql-components/Auth.vue @@ -0,0 +1,205 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/ChooseExternalEditor.cy.tsx b/packages/frontend-shared/src/gql-components/ChooseExternalEditor.cy.tsx new file mode 100644 index 0000000000..55d92da976 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ChooseExternalEditor.cy.tsx @@ -0,0 +1,52 @@ +import ChooseExternalEditor from './ChooseExternalEditor.vue' +import { ChooseExternalEditorFragmentDoc } from '../generated/graphql-test' +import { defaultMessages } from '@cy/i18n' + +describe('ChooseExternalEditor', { viewportHeight: 400, viewportWidth: 300 }, () => { + it('renders editors and UI elements work', () => { + cy.mountFragment(ChooseExternalEditorFragmentDoc, { + onResult (result) { + result.localSettings.availableEditors = [ + { id: 'computer', name: 'On Computer', binary: 'computer', __typename: 'Editor' }, + { id: 'atom', name: 'Atom', binary: 'atom', __typename: 'Editor' }, + { id: 'vim', name: 'Vim', binary: 'vim', __typename: 'Editor' }, + ] + }, + render: (gql) => { + return
+ }, + }) + + cy.contains(defaultMessages.settingsPage.editor.noEditorSelectedPlaceholder) + .should('be.visible') + .as('chooseEditor') + + // initial + cy.percySnapshot() + + cy.get('@chooseEditor').click() + cy.contains('On Computer').should('be.visible') + cy.contains('Atom').should('be.visible') + cy.contains('Vim').should('be.visible') + + cy.percySnapshot('open') + + cy.contains('Vim').click() + cy.contains('Vim').should('be.visible') + cy.contains('Atom').should('not.exist') + + cy.percySnapshot('selected') + + cy.get('[data-cy="custom-editor"]').should('not.exist') + + cy.get('@chooseEditor').click() + cy.contains('Custom').click() + cy.get('[data-cy="custom-editor"]').should('exist') + + cy.findByLabelText(defaultMessages.settingsPage.editor.customPathPlaceholder) + .type('test/path') + .should('have.value', 'test/path') + + cy.percySnapshot('custom editor input') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/ChooseExternalEditor.vue b/packages/frontend-shared/src/gql-components/ChooseExternalEditor.vue new file mode 100644 index 0000000000..bc6d037fb2 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ChooseExternalEditor.vue @@ -0,0 +1,171 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.cy.tsx b/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.cy.tsx new file mode 100644 index 0000000000..1efb4dfaf4 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.cy.tsx @@ -0,0 +1,58 @@ +import ChooseExternalEditorModal from './ChooseExternalEditorModal.vue' +import { ChooseExternalEditorFragmentDoc } from '../generated/graphql-test' +import { defaultMessages } from '@cy/i18n' + +describe('ChooseExternalEditorModal', () => { + it('renders editors and UI elements work', () => { + cy.mountFragment(ChooseExternalEditorFragmentDoc, { + onResult (result) { + result.localSettings.availableEditors = [ + { id: 'computer', name: 'On Computer', binary: 'computer', __typename: 'Editor' }, + { id: 'atom', name: 'Atom', binary: 'atom', __typename: 'Editor' }, + { id: 'vim', name: 'Vim', binary: 'vim', __typename: 'Editor' }, + ] + }, + render: (gql) => { + return
+ }, + }) + + cy.contains(defaultMessages.globalPage.externalEditorPreferences) + cy.contains(defaultMessages.globalPage.externalEditorPreferencesDescription1) + cy.contains(defaultMessages.globalPage.externalEditorPreferencesDescription2.replace('{0}', 'Settings')) + + cy.contains(defaultMessages.settingsPage.editor.noEditorSelectedPlaceholder) + .should('be.visible') + .as('chooseEditor') + + cy.contains('Need help').should('have.attr', 'href', 'https://on.cypress.io/file-opener-preference') + + // initial + cy.percySnapshot() + + cy.get('@chooseEditor').click() + cy.contains('On Computer').should('be.visible') + cy.contains('Atom').should('be.visible') + cy.contains('Vim').should('be.visible') + + cy.percySnapshot('open') + + cy.contains('Vim').click() + cy.contains('Vim').should('be.visible') + cy.contains('Atom').should('not.exist') + + cy.percySnapshot('selected') + + cy.get('[data-cy="custom-editor"]').should('not.exist') + + cy.get('@chooseEditor').click() + cy.contains('Custom').click() + cy.get('[data-cy="custom-editor"]').should('exist') + + cy.findByLabelText(defaultMessages.settingsPage.editor.customPathPlaceholder) + .type('test/path') + .should('have.value', 'test/path') + + cy.percySnapshot('custom editor input') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.vue b/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.vue new file mode 100644 index 0000000000..a5925ca4f3 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.vue @@ -0,0 +1,126 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/CopyButton.cy.tsx b/packages/frontend-shared/src/gql-components/CopyButton.cy.tsx new file mode 100644 index 0000000000..00c09f8c93 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/CopyButton.cy.tsx @@ -0,0 +1,37 @@ +import CopyButton from './CopyButton.vue' +import { Clipboard_CopyToClipboardDocument } from '../generated/graphql' + +describe('', { viewportHeight: 80, viewportWidth: 120 }, () => { + it('copies text to clipboard', () => { + cy.mount(() => (<> + + )) + .get('button') + .should('contain.text', 'Copy') + .get('svg') + .should('exist') + + const copyStub = cy.stub() + + cy.stubMutationResolver(Clipboard_CopyToClipboardDocument, (defineResult, { text }) => { + copyStub(text) + + return defineResult({ + copyTextToClipboard: true, + }) + }) + + cy.findByRole('button', { name: 'Copy' }).click() + cy.findByRole('button', { name: 'Copied!' }).should('be.visible') + + cy.wrap(copyStub).should('have.been.calledWith', 'Foobar') + }) + + it('noIcon hides the icon', () => { + cy.mount(() => (<> + + )) + .get('svg') + .should('not.exist') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/CopyButton.vue b/packages/frontend-shared/src/gql-components/CopyButton.vue new file mode 100644 index 0000000000..4acf22b761 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/CopyButton.vue @@ -0,0 +1,52 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/ExternalLink.cy.tsx b/packages/frontend-shared/src/gql-components/ExternalLink.cy.tsx new file mode 100644 index 0000000000..ad9c3b92fc --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ExternalLink.cy.tsx @@ -0,0 +1,93 @@ +import ExternalLink from './ExternalLink.vue' +import { ExternalLink_OpenExternalDocument } from '../generated/graphql' + +describe('', () => { + beforeEach(() => { + const onClickSpy = cy.spy().as('onClickSpy') + + cy.mount(() => ( + + Click me! + + )) + }) + + it('opens external link on click', () => { + const urlStub = cy.stub() + + cy.stubMutationResolver(ExternalLink_OpenExternalDocument, (defineResult, { url }) => { + urlStub(url) + + return defineResult({ + openExternal: true, + }) + }) + + cy.contains('a', 'Click me!') + .click() + + cy.wrap(urlStub).should('have.been.calledWith', 'https://on.cypress.io/ci') + cy.get('@onClickSpy').should('have.been.calledOnce') + }) + + it('opens external link on enter', () => { + const urlStub = cy.stub() + + cy.stubMutationResolver(ExternalLink_OpenExternalDocument, (defineResult, { url }) => { + urlStub(url) + + return defineResult({ + openExternal: true, + }) + }) + + cy.contains('a', 'Click me!') + .focus() + .realPress('Enter') + + cy.wrap(urlStub).should('have.been.calledWith', 'https://on.cypress.io/ci') + cy.get('@onClickSpy').should('have.been.calledOnce') + }) + + it('opens external link on click and enter', () => { + const urlStub = cy.stub() + + cy.stubMutationResolver(ExternalLink_OpenExternalDocument, (defineResult, { url }) => { + urlStub(url) + + return defineResult({ + openExternal: true, + }) + }) + + cy.contains('a', 'Click me!') + .click() + .realPress('Enter') + + cy.wrap(urlStub).should('have.been.calledTwice') + cy.get('@onClickSpy').should('have.been.calledTwice') + }) + + it('do not open external link on space bar trigger', () => { + const urlStub = cy.stub() + + cy.stubMutationResolver(ExternalLink_OpenExternalDocument, (defineResult, { url }) => { + urlStub(url) + + return defineResult({ + openExternal: true, + }) + }) + + cy.contains('a', 'Click me!') + .focus() + .realPress('Space') + + cy.wrap(urlStub).should('not.be.called') + cy.get('@onClickSpy').should('not.be.called') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/ExternalLink.vue b/packages/frontend-shared/src/gql-components/ExternalLink.vue new file mode 100644 index 0000000000..b901bf5bc3 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/ExternalLink.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/packages/frontend-shared/src/gql-components/HeaderBar.vue b/packages/frontend-shared/src/gql-components/HeaderBar.vue new file mode 100644 index 0000000000..9d17d4896f --- /dev/null +++ b/packages/frontend-shared/src/gql-components/HeaderBar.vue @@ -0,0 +1,37 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/HeaderBarContent.cy.tsx b/packages/frontend-shared/src/gql-components/HeaderBarContent.cy.tsx new file mode 100644 index 0000000000..dcbb6fca65 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/HeaderBarContent.cy.tsx @@ -0,0 +1,384 @@ +import { HeaderBar_HeaderBarContentFragmentDoc } from '../generated/graphql-test' +import HeaderBarContent from './HeaderBarContent.vue' +import { defaultMessages } from '@cy/i18n' + +const text = defaultMessages.topNav + +describe('', { viewportWidth: 1000, viewportHeight: 750 }, () => { + it('renders with functional browser menu when show-browsers prop is true', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.percySnapshot('before browsers open') + + cy.get('[data-cy="top-nav-active-browser"]') + .should('be.visible') + .click() + + cy.contains('Edge Canary') + .should('be.visible') + .closest('[data-cy="top-nav-browser-list-item"]') + .within(() => { + cy.get('[data-cy="unsupported-browser-tooltip"]') + .should('not.exist') + }) + + cy.contains('Version unsupported') + .should('be.visible') + .closest('[data-cy="top-nav-browser-list-item"]') + .within(() => { + cy.get('[data-cy="unsupported-browser-tooltip"]') + .should('exist') + }) + + cy.percySnapshot('after browsers open') + }), + + it('renders without browser menu by default and other items work', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.contains('Projects').should('be.visible') + cy.get('[data-cy="top-nav-active-browser"]').should('not.exist') + cy.percySnapshot() + cy.contains('button', text.docsMenu.docsHeading).click() + + cy.wrap(Object.values(text.docsMenu)).each((menuItem) => { + if (typeof menuItem === 'string') { + cy.contains(menuItem).should('be.visible') + } + }) + + cy.percySnapshot() + cy.get('body').click() + cy.contains('a', text.docsMenu.firstTest).should('not.be.visible') + }) + + it('docs menu has expected links with no current project', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + result.currentProject = null + }, + render: (gqlVal) => ( +
+ +
+ ), + }) + + // we render without a current project to validate ciSetup and fasterTests links + // because outside of global mode, those are buttons that trigger popups + // so this way we can assert all links at once. + const expectedDocsLinks = { + [text.docsMenu.firstTest]: 'https://on.cypress.io/writing-first-test?utm_medium=Docs+Menu&utm_content=First+Test', + [text.docsMenu.testingApp]: 'https://on.cypress.io/testing-your-app?utm_medium=Docs+Menu&utm_content=Testing+Your+App', + [text.docsMenu.organizingTests]: 'https://on.cypress.io/writing-and-organizing-tests?utm_medium=Docs+Menu&utm_content=Organizing+Tests', + [text.docsMenu.bestPractices]: 'https://on.cypress.io/best-practices?utm_medium=Docs+Menu&utm_content=Best+Practices', + [text.docsMenu.configuration]: 'https://on.cypress.io/configuration?utm_medium=Docs+Menu&utm_content=Configuration', + [text.docsMenu.api]: 'https://on.cypress.io/api?utm_medium=Docs+Menu&utm_content=API', + [text.docsMenu.ciSetup]: 'https://on.cypress.io/ci?utm_medium=Docs+Menu&utm_content=Set+Up+CI', + [text.docsMenu.fasterTests]: 'https://on.cypress.io/parallelization?utm_medium=Docs+Menu&utm_content=Parallelization', + } + + cy.contains('button', text.docsMenu.docsHeading).click() + + cy.wrap(Object.keys(expectedDocsLinks)).each((linkName: string) => { + cy.contains('a', linkName).should('have.attr', 'href', expectedDocsLinks[linkName]) + }) + }) + + it('does not show hint when on latest version of Cypress', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + result.versions = { + __typename: 'VersionData', + latest: { + __typename: 'Version', + id: '8.7.0', + version: '8.7.0', + released: '2021-10-25T21:00:00.000Z', + }, + current: { + __typename: 'Version', + id: '8.7.0', + version: '8.7.0', + released: '2021-10-25T21:00:00.000Z', + }, + } + }, + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.contains('a', '8.7.0').should('be.visible').and('have.attr', 'href', 'https://on.cypress.io/changelog#8-7-0') + cy.percySnapshot() + }) + + it('shows hint and modal to upgrade to latest version of cypress', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + if (result.currentProject) { + result.currentProject.packageManager = 'yarn' + } + + result.versions = { + __typename: 'VersionData', + current: { + __typename: 'Version', + id: '8.6.0', + version: '8.6.0', + released: '2021-06-25T21:00:00.000Z', + }, + latest: { + __typename: 'Version', + id: '8.7.0', + version: '8.7.0', + released: '2021-10-25T21:00:00.000Z', + }, + } + }, + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.contains('v8.6.0 โ€ข Upgrade').should('be.visible') + cy.percySnapshot('before upgrade click') + cy.contains('v8.6.0 โ€ข Upgrade').click() + cy.get('[data-cy="latest-version"]').contains('8.7.0') + cy.get('[data-cy="current-version"]').contains('8.6.0') + cy.get('[data-cy="update-hint"]').should('be.visible') + cy.percySnapshot('after upgrade click') + cy.contains('button', 'Update to').click() + + cy.contains(`${defaultMessages.topNav.updateCypress.title} 8.7.0`).should('be.visible') + cy.contains('test-project').should('be.visible') + cy.contains('code', 'yarn add -D cypress').should('be.visible') + cy.percySnapshot('after upgrade modal open') + + cy.get('body').type('{esc}') // dismiss modal with keyboard + cy.contains(`${defaultMessages.topNav.updateCypress.title} 8.7.0`).should('not.exist') + }) + + it('displays the active project name', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.contains('test-project').should('be.visible') + }) + + it('the login modal reaches "opening browser" status', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.findByRole('button', { name: text.login.actionLogin }) + .click() + + cy.contains('h2', text.login.titleInitial).should('be.visible') + cy.percySnapshot() + + cy.findByRole('button', { name: text.login.actionLogin }) + .should('be.visible') + .and('have.focus') + + cy.findByRole('button', { name: defaultMessages.actions.close }).click() + + cy.contains('h2', text.login.titleInitial).should('not.exist') + }) + + it('the logged in state is correctly presented in header', () => { + const cloudViewer = { + id: '1', + email: 'test@test.test', + fullName: 'Tester Test', + } + + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + result.__typename = 'Query' + result.authState.browserOpened = true + result.cloudViewer = cloudViewer + result.cloudViewer.__typename = 'CloudUser' + }, + render: (gqlVal) =>
, + }) + + cy.findByRole('button', { name: text.login.profileMenuLabel }).click() + cy.contains(cloudViewer.fullName).should('be.visible') + cy.contains(cloudViewer.email).should('be.visible') + cy.findByRole('button', { name: text.login.actionLogout }).should('be.visible') + cy.percySnapshot() + }) + + it('Shows a page name instead of project when a page name is provided', () => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.contains('Project').should('not.exist') + cy.contains('Test Page').should('be.visible') + }) + + describe('prompts', () => { + describe('the CI prompt', () => { + context('opens on click', () => { + beforeEach(() => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.contains('Docs').click() + cy.contains('Set up CI').click() + }) + + it('opens on menu item click', () => { + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('be.visible') + cy.percySnapshot() + }) + + it('is dismissible from X icon', () => { + cy.findAllByLabelText('Close').click() + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('not.exist') + }) + }) + + context('opens automatically', () => { + beforeEach(() => { + cy.clock(1609891200000) + }) + + function mountWithSavedState (options?: {state?: object, projectId?: string }) { + return cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + if (!result.currentProject) { + return + } + + result.currentProject.savedState = { + firstOpened: 1609459200000, + lastOpened: 1609459200000, + promptsShown: {}, + ...(options?.state ?? {}), + } + + const projectId = result.currentProject.config.find((item: {field: string, value: string}) => item.field = 'projectId') + + if (projectId) { + projectId.value = options?.projectId + } + }, + render: (gqlVal) =>
, + }) + } + + it('opens when after 4 days from first open, no projectId, and not already shown', () => { + mountWithSavedState() + + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('be.visible') + }) + + it('links have correct utm_content param', () => { + mountWithSavedState() + + cy.contains( + 'a[href="https://on.cypress.io/setup-ci?utm_medium=CI+Prompt+1&utm_campaign=Other&utm_content=Automatic"]', + defaultMessages.topNav.docsMenu.prompts.ci1.seeOtherGuides, + ).should('be.visible') + + cy.contains( + 'a[href="https://on.cypress.io/ci?utm_medium=CI+Prompt+1&utm_campaign=Learn+More"]', + defaultMessages.topNav.docsMenu.prompts.ci1.intro, + ).should('be.visible') + }) + + it('does not open when projectId exists', () => { + mountWithSavedState({ projectId: 'testid' }) + + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('not.exist') + }) + + it('does not open when previously shown', () => { + mountWithSavedState({ state: { promptsShown: { 'ci1': 1609459200000, 'orchestration1': 1609459200000 } } }) + + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('not.exist') + }) + + it('does not open when another prompt has been shown recently', () => { + mountWithSavedState({ state: { promptsShown: { dashboard1: 1609891100000 } } }) + + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('not.exist') + }) + + it('does not open if "allowAutomaticPromptOpen" prop is not true', () => { + // we should be sure that, eg, in launchpad, this would not open up after a testing type is configured + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + onResult: (result) => { + if (!result.currentProject) { + return + } + + result.currentProject.savedState = { + firstOpened: 1609459200000, + lastOpened: 1609459200000, + promptsShown: {}, + } + }, + render: (gqlVal) =>
, + }) + + cy.contains(defaultMessages.topNav.docsMenu.prompts.ci1.description).should('not.exist') + }) + }) + }) + + describe('the orchestration prompt', () => { + it('is not open by default', () => { + cy.get('.prompt-orchestration1').should('not.exist') + }) + + context('opens on click', () => { + beforeEach(() => { + cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.contains('Docs').click() + cy.contains('Run tests faster').click() + }) + + it('opens on menu item click', () => { + cy.percySnapshot() + cy.contains(defaultMessages.topNav.docsMenu.prompts.orchestration1.title).should('be.visible') + cy.contains('Getting Started').should('not.exist') + }) + + it('is dismissible from X icon', () => { + cy.findAllByLabelText('Close').click() + cy.contains(defaultMessages.topNav.docsMenu.prompts.orchestration1.title).should('not.exist') + }) + + it('links to more information with expected utm params', () => { + cy.contains( + 'a[href="https://on.cypress.io/smart-orchestration?utm_medium=CI+Prompt+1&utm_campaign=Learn+More"]', + defaultMessages.topNav.docsMenu.prompts.orchestration1.learnMore, + ) + .should('be.visible') + }) + }) + }) + }) +}) diff --git a/packages/frontend-shared/src/gql-components/HeaderBarContent.vue b/packages/frontend-shared/src/gql-components/HeaderBarContent.vue new file mode 100644 index 0000000000..b089be86f5 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/HeaderBarContent.vue @@ -0,0 +1,265 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/OpenConfigFileInIDE.vue b/packages/frontend-shared/src/gql-components/OpenConfigFileInIDE.vue new file mode 100644 index 0000000000..eb894b8607 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/OpenConfigFileInIDE.vue @@ -0,0 +1,39 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/OpenFileInIDE.vue b/packages/frontend-shared/src/gql-components/OpenFileInIDE.vue new file mode 100644 index 0000000000..6ed7b51b65 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/OpenFileInIDE.vue @@ -0,0 +1,81 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/StatusBadge.cy.tsx b/packages/frontend-shared/src/gql-components/StatusBadge.cy.tsx new file mode 100644 index 0000000000..7fa4ebef9e --- /dev/null +++ b/packages/frontend-shared/src/gql-components/StatusBadge.cy.tsx @@ -0,0 +1,31 @@ +import { ref } from 'vue' +import StatusBadge from './StatusBadge.vue' +import Button from '../components/Button.vue' + +describe('', () => { + it('renders and toggles', { viewportWidth: 500, viewportHeight: 200 }, () => { + const status = ref(false) + + cy.mount(() => ( +
+ +

+ {// @ts-ignore + } +
+ )) + + cy.findByText('not configured').should('be.visible') + cy.percySnapshot() + cy.findByText('toggle').click() + cy.findByText('configured').should('be.visible') + cy.percySnapshot() + }) +}) diff --git a/packages/frontend-shared/src/gql-components/StatusBadge.vue b/packages/frontend-shared/src/gql-components/StatusBadge.vue new file mode 100644 index 0000000000..1f7c87d819 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/StatusBadge.vue @@ -0,0 +1,110 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/TestingTypePicker.cy.tsx b/packages/frontend-shared/src/gql-components/TestingTypePicker.cy.tsx new file mode 100644 index 0000000000..e3798a5105 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/TestingTypePicker.cy.tsx @@ -0,0 +1,43 @@ +import TestingTypePicker from './TestingTypePicker.vue' +import { TestingTypePickerFragmentDoc } from '../generated/graphql-test' +import { defaultMessages } from '@cy/i18n' + +const { component, e2e } = defaultMessages.testingType + +describe('TestingTypePicker', () => { + it('renders "configured" and "not configured" states', () => { + const pick = cy.spy().as('pick') + + cy.mountFragment(TestingTypePickerFragmentDoc, { + onResult (result) { + if (result.currentProject) { + result.currentProject.isCTConfigured = true + result.currentProject.isE2EConfigured = false + } + }, + render: (gql) => { + return + }, + }) + + cy.get('[data-cy-testingtype="e2e"]').within(() => { + cy.contains(e2e.name).should('be.visible') + cy.contains(e2e.description).should('be.visible') + cy.contains(defaultMessages.setupPage.testingCard.notConfigured).should('be.visible') + }) + + cy.get('[data-cy-testingtype="component"]').within(() => { + cy.contains(component.name).should('be.visible') + cy.contains(component.description).should('be.visible') + cy.contains(defaultMessages.setupPage.testingCard.configured).should('be.visible') + }) + + cy.percySnapshot('before click') + + cy.contains(e2e.name).click() + cy.contains(component.name).click() + cy.get('@pick').should('have.been.calledTwice') + + cy.percySnapshot('after click - focus') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/TestingTypePicker.vue b/packages/frontend-shared/src/gql-components/TestingTypePicker.vue new file mode 100644 index 0000000000..57c58a1b8d --- /dev/null +++ b/packages/frontend-shared/src/gql-components/TestingTypePicker.vue @@ -0,0 +1,94 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/DocsMenuContent.vue b/packages/frontend-shared/src/gql-components/topnav/DocsMenuContent.vue new file mode 100644 index 0000000000..7969a423d8 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/DocsMenuContent.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/LoginModal.cy.tsx b/packages/frontend-shared/src/gql-components/topnav/LoginModal.cy.tsx new file mode 100644 index 0000000000..6d7600295d --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/LoginModal.cy.tsx @@ -0,0 +1,196 @@ +import { LoginModalFragmentDoc } from '../../generated/graphql-test' +import LoginModal from './LoginModal.vue' +import { defaultMessages } from '@cy/i18n' + +const text = defaultMessages.topNav + +const cloudViewer = { + id: '1', + email: 'test@test.test', + fullName: 'Tester Test', +} + +const cloudViewerNoName = { + id: '2', + email: 'no.name@test.test', + fullName: null, +} + +type TestCloudViewer = { + __typename?: 'CloudUser' | undefined + id: string + email: string | null + fullName: string | null +} + +const mountSuccess = (viewer: TestCloudViewer = cloudViewer) => { + cy.mountFragment(LoginModalFragmentDoc, { + onResult: (result) => { + result.__typename = 'Query' + result.authState.browserOpened = true + result.cloudViewer = viewer + result.cloudViewer.__typename = 'CloudUser' + }, + render: (gqlVal) =>
, + }) +} + +describe('', { viewportWidth: 1000, viewportHeight: 750 }, () => { + describe('progress communication', () => { + it('renders and reaches "opening browser" status', () => { + cy.mountFragment(LoginModalFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.contains('h2', text.login.titleInitial).should('be.visible') + + // begin the login process + cy.findByRole('button', { name: text.login.actionLogin }).click() + + // ensure we reach "browser is opening" status on the CTA + cy.findByRole('button', { name: text.login.actionOpening }) + .should('be.visible') + .and('be.disabled') + }) + + it('shows correct "waiting for login" status', () => { + cy.mountFragment(LoginModalFragmentDoc, { + render: (gqlVal) => { + gqlVal.authState.browserOpened = true + + return
+ }, + }) + + // The LoginModal immediately shows the "Waiting..." button + // if the browser already opened + cy.findByRole('button', { name: text.login.actionWaiting }) + .should('be.visible') + .and('be.disabled') + }) + + it('shows successful login status', () => { + mountSuccess() + cy.contains('h2', text.login.titleSuccess).should('be.visible') + cy.contains(text.login.bodySuccess.replace('{0}', cloudViewer.fullName)).should('be.visible') + cy.contains('a', cloudViewer.fullName).should('have.attr', 'href', 'https://on.cypress.io/dashboard/profile') + }) + }) + + describe('errors', () => { + it('shows an error state when browser cannot be launched', () => { + const authUrl = 'http://127.0.0.1:0000/redirect-to-auth' + + cy.mountFragment(LoginModalFragmentDoc, { + onResult: (result) => { + result.__typename = 'Query' + result.authState.name = 'AUTH_COULD_NOT_LAUNCH_BROWSER' + result.authState.message = 'http://127.0.0.1:0000/redirect-to-auth' + }, + render: (gqlVal) => + (
+ +
), + }) + + cy.contains('button', text.login.actionTryAgain).should('not.be.visible') + cy.contains('button', text.login.actionCancel).should('not.be.visible') + cy.contains(text.login.titleBrowserError).should('be.visible') + cy.contains(text.login.bodyBrowserError).should('be.visible') + cy.contains(text.login.bodyBrowserErrorDetails).should('be.visible') + cy.contains(authUrl).should('be.visible') + cy.contains('button', 'Copy').should('be.visible') + }) + + it('shows non-browser errors from login process', () => { + const updateSpy = cy.spy().as('updateSpy') + const methods = { + 'onUpdate:modelValue': (newValue) => { + updateSpy(newValue) + }, + } + const errorText = 'The flux capacitor ran out of battery' + + cy.mountFragment(LoginModalFragmentDoc, { + render: (gqlVal) => { + gqlVal.authState.name = 'AUTH_ERROR_DURING_LOGIN' + gqlVal.authState.message = errorText + + return (
+ +
) + }, + }) + + cy.contains(text.login.titleFailed).should('be.visible') + cy.contains(text.login.bodyError).should('be.visible') + cy.contains(errorText).should('be.visible') + + // we test the qql mutation behavior of these buttons from e2e tests + cy.contains('button', text.login.actionTryAgain).should('be.visible') + + // but we can test that cancelling closes the modal here: + cy.contains('button', text.login.actionCancel).click() + cy.get('@updateSpy').should('have.been.calledWith', false) + }) + }) + + it('shows successful login status with email if name not provided', () => { + mountSuccess(cloudViewerNoName) + cy.contains('h2', text.login.titleSuccess).should('be.visible') + cy.contains(text.login.bodySuccess.replace('{0}', cloudViewerNoName.email)).should('be.visible') + cy.contains('a', cloudViewerNoName.email).should('have.attr', 'href', 'https://on.cypress.io/dashboard/profile') + }) + + it('emits an event to close the modal when "Continue" button is clicked', () => { + mountSuccess() + cy.findByRole('button', { name: text.login.actionContinue }).click().then(() => { + cy.wrap(Cypress.vueWrapper.findComponent(LoginModal).emitted('update:modelValue')?.[0]) + .should('deep.equal', [false]) + }) + }) + + describe('no internet connection', () => { + afterEach(() => { + cy.goOnline() + }) + + it('renders correct components if there is no internet connection', () => { + cy.mountFragment(LoginModalFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.goOffline() + + cy.contains('You have no internet connection') + cy.findByRole('button', { name: text.login.actionLogin }) + .should('be.visible') + .and('be.disabled') + }) + + it('shows login action when the internet is back', () => { + cy.mountFragment(LoginModalFragmentDoc, { + render: (gqlVal) =>
, + }) + + cy.goOffline() + + cy.contains('You have no internet connection') + cy.findByRole('button', { name: text.login.actionLogin }) + .should('be.visible') + .and('be.disabled') + + cy.goOnline() + + cy.contains('h2', text.login.titleInitial).should('be.visible') + + // begin the login process + cy.findByRole('button', { name: text.login.actionLogin }).click() + + // ensure we reach "browser is opening" status on the CTA + cy.findByRole('button', { name: text.login.actionOpening }) + .should('be.visible') + .and('be.disabled') + }) + }) +}) diff --git a/packages/frontend-shared/src/gql-components/topnav/LoginModal.vue b/packages/frontend-shared/src/gql-components/topnav/LoginModal.vue new file mode 100644 index 0000000000..6373934800 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/LoginModal.vue @@ -0,0 +1,162 @@ + + diff --git a/packages/frontend-shared/src/gql-components/topnav/PromptContent.cy.tsx b/packages/frontend-shared/src/gql-components/topnav/PromptContent.cy.tsx new file mode 100644 index 0000000000..8cf0fbcf01 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/PromptContent.cy.tsx @@ -0,0 +1,35 @@ +import PromptContent from './PromptContent.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', { viewportWidth: 500, viewportHeight: 800 }, () => { + const { ci1, orchestration1 } = defaultMessages.topNav.docsMenu.prompts + const expectedContent = [...Object.values(ci1), ...Object.values(orchestration1)] + + it('renders with expected content', () => { + cy.mount({ + render: () => { + return (
+

{ci1.title}

+ +
+

{orchestration1.title}

+ +
) + }, + }) + + expectedContent.forEach((text) => { + cy.contains(text as string).should('be.visible') + }) + + // links populate with params + cy.get('[data-testid="provider-list"] li') + .should('have.length', 6) + .eq(0) + .find('a') + .should('have.attr', 'href', 'https://on.cypress.io/setup-ci-circleci?utm_medium=CI+Prompt+1&utm_campaign=Circle&utm_content=Manual') + + cy.contains('a', defaultMessages.topNav.docsMenu.prompts.ci1.intro) + .should('have.attr', 'href', 'https://on.cypress.io/ci?utm_medium=CI+Prompt+1&utm_campaign=Learn+More') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/topnav/PromptContent.vue b/packages/frontend-shared/src/gql-components/topnav/PromptContent.vue new file mode 100644 index 0000000000..11310905e1 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/PromptContent.vue @@ -0,0 +1,241 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/TopNav.vue b/packages/frontend-shared/src/gql-components/topnav/TopNav.vue new file mode 100644 index 0000000000..f658b6c1af --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/TopNav.vue @@ -0,0 +1,357 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/TopNavList.vue b/packages/frontend-shared/src/gql-components/topnav/TopNavList.vue new file mode 100644 index 0000000000..22f14c20b2 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/TopNavList.vue @@ -0,0 +1,56 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/TopNavListItem.vue b/packages/frontend-shared/src/gql-components/topnav/TopNavListItem.vue new file mode 100644 index 0000000000..d95f395f38 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/TopNavListItem.vue @@ -0,0 +1,30 @@ + + diff --git a/packages/frontend-shared/src/gql-components/topnav/UnsupportedBrowserTooltip.vue b/packages/frontend-shared/src/gql-components/topnav/UnsupportedBrowserTooltip.vue new file mode 100644 index 0000000000..387b1a148d --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/UnsupportedBrowserTooltip.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.cy.tsx b/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.cy.tsx new file mode 100644 index 0000000000..112c038fc1 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.cy.tsx @@ -0,0 +1,42 @@ +import UpdateCypressModal from './UpdateCypressModal.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', { viewportWidth: 1000, viewportHeight: 750 }, () => { + const installedVersion = '8.2.0' + const latestVersion = '10.0.0' + + it('renders expected content & emits expected events', () => { + const handleClose = cy.stub() + + cy.mount(() => ()) + + cy.contains(`${defaultMessages.topNav.updateCypress.title} ${latestVersion}`).should('be.visible') + cy.contains(defaultMessages.topNav.updateCypress.currentlyRunning + .replace('{0}', installedVersion)).should('be.visible') + + cy.contains(defaultMessages.topNav.updateCypress.pasteToUpgradeGlobal + .replace('{0}', defaultMessages.topNav.updateCypress.rememberToCloseInsert)).should('be.visible') + + cy.contains(`cypress@${latestVersion}`).should('be.visible') + cy.findByLabelText('Close').click().then(() => { + expect(handleClose).to.have.been.calledOnce + }) + }) + + it('renders project-specific instructions when a project name prop is present', () => { + cy.mount(() => ()) + + cy.contains(defaultMessages.topNav.updateCypress.pasteToUpgradeProject + .replace('{0}', defaultMessages.topNav.updateCypress.rememberToCloseInsert)).should('be.visible') + }) +}) diff --git a/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.vue b/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.vue new file mode 100644 index 0000000000..0c90463d3c --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/UpdateCypressModal.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/UserAvatar.cy.tsx b/packages/frontend-shared/src/gql-components/topnav/UserAvatar.cy.tsx new file mode 100644 index 0000000000..f74187afee --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/UserAvatar.cy.tsx @@ -0,0 +1,29 @@ +import UserAvatar from './UserAvatar.vue' + +describe('', { viewportWidth: 48, viewportHeight: 48 }, () => { + it('renders when an email address is passed', () => { + cy.mount(() => ) + validateUserAvatar() + cy.percySnapshot() + }) + + it('renders when a null email address is passed', () => { + cy.mount(() => ) + validateUserAvatar() + }) + + it('renders when no email address is passed', () => { + cy.mount(() => ) + validateUserAvatar() + }) + + function validateUserAvatar () { + cy.get('[data-cy="user-avatar"]') + .should('be.visible') + .should(($el) => { + // general health check that that gravatar url was used in the DOM, + // since it does not contain explicit parameters like email address to check + expect($el[0].outerHTML).to.contain('gravatar.com/avatar') + }) + } +}) diff --git a/packages/frontend-shared/src/gql-components/topnav/UserAvatar.vue b/packages/frontend-shared/src/gql-components/topnav/UserAvatar.vue new file mode 100644 index 0000000000..9308940773 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/UserAvatar.vue @@ -0,0 +1,26 @@ + + + diff --git a/packages/frontend-shared/src/gql-components/topnav/VerticalBrowserListItems.vue b/packages/frontend-shared/src/gql-components/topnav/VerticalBrowserListItems.vue new file mode 100644 index 0000000000..12bdeff96b --- /dev/null +++ b/packages/frontend-shared/src/gql-components/topnav/VerticalBrowserListItems.vue @@ -0,0 +1,144 @@ + + diff --git a/packages/frontend-shared/src/gql-components/useClipboard.ts b/packages/frontend-shared/src/gql-components/useClipboard.ts new file mode 100644 index 0000000000..c0f00e2507 --- /dev/null +++ b/packages/frontend-shared/src/gql-components/useClipboard.ts @@ -0,0 +1,42 @@ +/** + * Using the clipboard API from electron instead of the browser's navigator API, + * we avoid the safety measures from the browser. + * This way, regardless of the browser, we can use and test the clipboard. + */ +import { Clipboard_CopyToClipboardDocument } from '../generated/graphql' +import { gql, useMutation } from '@urql/vue' +import { ref } from 'vue' + +gql` +mutation Clipboard_CopyToClipboard($text: String!) { + copyTextToClipboard(text: $text) +} +` + +interface ClipboardOptions { + // time it takes in MS for the copied message to disappear + copiedDuring?: number +} + +export function useClipboard (options: ClipboardOptions = {}) { + const copyMutation = useMutation(Clipboard_CopyToClipboardDocument) + const copied = ref(false) + + let timer: NodeJS.Timeout | undefined + + const copy = async (text: string) => { + const { data } = await copyMutation.executeMutation({ text }) + + copied.value = data?.copyTextToClipboard ?? false + if (timer) { + clearTimeout(timer) + } + + timer = setTimeout(() => { + copied.value = false + timer = undefined + }, options.copiedDuring || 2000) + } + + return { copy, copied } +} diff --git a/packages/frontend-shared/src/gql-components/useExternalLink.ts b/packages/frontend-shared/src/gql-components/useExternalLink.ts new file mode 100644 index 0000000000..1a1a02414f --- /dev/null +++ b/packages/frontend-shared/src/gql-components/useExternalLink.ts @@ -0,0 +1,24 @@ +import { ExternalLink_OpenExternalDocument } from '../generated/graphql' +import { gql, useMutation } from '@urql/vue' +import type { MaybeRef } from '@vueuse/core' +import { unref } from 'vue' + +gql` +mutation ExternalLink_OpenExternal ($url: String!, $includeGraphqlPort: Boolean) { + openExternal(url: $url, includeGraphqlPort: $includeGraphqlPort) +} +` + +export const useExternalLink = ($href?: MaybeRef, includeGraphqlPort: boolean = false) => { + const openExternalMutation = useMutation(ExternalLink_OpenExternalDocument) + + return (href?: string) => { + const resolvedHref = unref(typeof href === 'string' ? href : $href) + + if (!resolvedHref) { + return new Error(`Cannot open external link. Possible urls passed in were ${{ localHref: href, initialHref: unref($href) }}`) + } + + return openExternalMutation.executeMutation({ url: resolvedHref, includeGraphqlPort }) + } +} diff --git a/packages/frontend-shared/src/graphql/urqlClient.ts b/packages/frontend-shared/src/graphql/urqlClient.ts new file mode 100644 index 0000000000..39edf45b9c --- /dev/null +++ b/packages/frontend-shared/src/graphql/urqlClient.ts @@ -0,0 +1,188 @@ +import type { Exchange, Client } from '@urql/core' +import { + createClient, + dedupExchange, + errorExchange, + fetchExchange, + subscriptionExchange, +} from '@urql/core' +import { devtoolsExchange } from '@urql/devtools' +import { useToast } from 'vue-toastification' +import type { Socket } from '@packages/socket/lib/browser' +import { client } from '@packages/socket/lib/browser' +import { createClient as createWsClient } from 'graphql-ws' + +import { cacheExchange as graphcacheExchange } from '@urql/exchange-graphcache' +import { urqlCacheKeys } from '@packages/data-context/src/util/urqlCacheKeys' + +import { urqlSchema } from '../generated/urql-introspection.gen' + +import { pubSubExchange } from './urqlExchangePubsub' +import { namedRouteExchange } from './urqlExchangeNamedRoute' +import type { SpecFile, AutomationElementId, Browser } from '@packages/types' +import { urqlFetchSocketAdapter } from './urqlFetchSocketAdapter' + +const toast = useToast() + +export function makeCacheExchange (schema: any = urqlSchema) { + return graphcacheExchange({ ...urqlCacheKeys, schema }) +} + +declare global { + interface Window { + ws?: Socket + /** + * We can set this in onBeforeLoad in Cypress tests, allowing us + * to use cy.intercept in tests that we need it + */ + __CYPRESS_GQL_NO_SOCKET__?: string + __CYPRESS_MODE__: 'run' | 'open' + __RUN_MODE_SPECS__: SpecFile[] + __CYPRESS_TESTING_TYPE__: 'e2e' | 'component' + __CYPRESS_BROWSER__: Partial & {majorVersion: string | number} + __CYPRESS_CONFIG__: { + base64Config: string + namespace: AutomationElementId + } + } +} + +const cypressInRunMode = window.top === window && window.__CYPRESS_MODE__ === 'run' + +interface LaunchpadUrqlClientConfig { + target: 'launchpad' +} + +interface AppUrqlClientConfig { + target: 'app' + namespace: string + socketIoRoute: string +} + +export type UrqlClientConfig = LaunchpadUrqlClientConfig | AppUrqlClientConfig + +export async function makeUrqlClient (config: UrqlClientConfig): Promise { + let hasError = false + + const exchanges: Exchange[] = [dedupExchange] + + const io = window.ws ?? getPubSubSource(config) + + const connectPromise = new Promise((resolve) => { + io.once('connect', resolve) + }) + + const socketClient = getSocketSource(config) + + // GraphQL and urql are not used in app + run mode, so we don't add the + // pub sub exchange. + if (config.target === 'launchpad' || config.target === 'app' && !cypressInRunMode) { + // If we're in the launchpad, we connect to the known GraphQL Socket port, + // otherwise we connect to the /__socket of the current domain, unless we've explicitly + + exchanges.push(pubSubExchange(io)) + } + + exchanges.push( + errorExchange({ + onError (error) { + const message = ` + GraphQL Field Path: [${error.graphQLErrors?.[0]?.path?.join(', ')}]: + + ${error.message} + + ${error.stack ?? ''} + ` + + if (process.env.NODE_ENV !== 'production' && !hasError) { + hasError = true + toast.error(message, { + timeout: false, + onClose () { + hasError = false + }, + }) + } + + // eslint-disable-next-line + console.error(error) + }, + }), + // https://formidable.com/open-source/urql/docs/graphcache/errors/ + makeCacheExchange(), + namedRouteExchange, + fetchExchange, + subscriptionExchange({ + forwardSubscription (op) { + return { + subscribe: (sink) => { + // @ts-ignore + const dispose = socketClient.subscribe(op, sink) + + return { + unsubscribe: dispose, + } + }, + } + }, + }), + ) + + if (import.meta.env.DEV) { + exchanges.unshift(devtoolsExchange) + } + + const url = config.target === 'launchpad' ? `/__launchpad/graphql` : `/${config.namespace}/graphql` + + const client = createClient({ + url, + requestPolicy: cypressInRunMode ? 'cache-only' : 'cache-first', + exchanges, + + // Rather than authoring a custom exchange, let's just polyfill the "fetch" + // exchange to adapt to a similar interface. This way it'll be simple to + // swap in-and-out during integration tests. + fetch: config.target === 'launchpad' || window.__CYPRESS_GQL_NO_SOCKET__ ? window.fetch : urqlFetchSocketAdapter(io), + }) + + await connectPromise + + return client +} + +interface LaunchpadPubSubConfig { + target: 'launchpad' +} + +interface AppPubSubConfig { + target: 'app' + socketIoRoute: string +} + +type PubSubConfig = LaunchpadPubSubConfig | AppPubSubConfig + +function getPubSubSource (config: PubSubConfig) { + if (config.target === 'launchpad') { + return client({ + path: '/__launchpad/socket', + transports: ['websocket'], + }) + } + + return client({ + path: config.socketIoRoute, + transports: ['websocket'], + }) +} + +function getSocketSource (config: UrqlClientConfig) { + // http: -> ws: & https: -> wss: + const protocol = window.location.protocol.replace('http', 'ws') + const wsUrl = config.target === 'launchpad' + ? `ws://${window.location.host}/__launchpad/graphql-ws` + : `${protocol}//${window.location.host}${config.socketIoRoute}-graphql` + + return createWsClient({ + url: wsUrl, + }) +} diff --git a/packages/frontend-shared/src/graphql/urqlExchangeNamedRoute.ts b/packages/frontend-shared/src/graphql/urqlExchangeNamedRoute.ts new file mode 100644 index 0000000000..3d3dc36e75 --- /dev/null +++ b/packages/frontend-shared/src/graphql/urqlExchangeNamedRoute.ts @@ -0,0 +1,26 @@ +import { getOperationName } from '@urql/core' +import type { Exchange } from '@urql/core' + +import { map, pipe } from 'wonka' + +export const namedRouteExchange: Exchange = ({ client, forward }) => { + return (ops$) => { + return forward(pipe( + ops$, + map((o) => { + // Only prefix the URL if it hasn't been already + if (!o.context.url.endsWith('/graphql')) { + return o + } + + return { + ...o, + context: { + ...o.context, + url: `${o.context.url}/${o.kind}-${getOperationName(o.query)}`, + }, + } + }), + )) + } +} diff --git a/packages/frontend-shared/src/graphql/urqlExchangePubsub.ts b/packages/frontend-shared/src/graphql/urqlExchangePubsub.ts new file mode 100644 index 0000000000..6c430e42f8 --- /dev/null +++ b/packages/frontend-shared/src/graphql/urqlExchangePubsub.ts @@ -0,0 +1,93 @@ +import { pipe, tap } from 'wonka' +import type { Exchange, Operation, OperationResult } from '@urql/core' +import type { Socket } from '@packages/socket/lib/browser' +import type { DefinitionNode, DocumentNode, OperationDefinitionNode } from 'graphql' + +export const pubSubExchange = (io: Socket): Exchange => { + return ({ client, forward }) => { + const watchedOperations = new Map() + const observedOperations = new Map() + // Keeps track of the operations we're expecting to re-query, + // but which haven't resolved yet on their initial request. + const awaitingMount: Record = {} + + function reexecuteOperation (op: Operation, refetchHeader = 'true') { + client.reexecuteOperation( + client.createRequestOperation('query', op, { + requestPolicy: 'cache-and-network', + fetchOptions: { + headers: { + 'x-cypress-graphql-refetch': refetchHeader, + }, + }, + }), + ) + } + + interface RefreshOnlyInfo { + operation: string + field: string + variables: any + } + + // Handles the refresh of the GraphQL operation + io.on('graphql-refresh', (refreshOnly?: RefreshOnlyInfo) => { + if (refreshOnly?.operation) { + const fieldHeader = `${refreshOnly.operation}.${refreshOnly.field}` + const toRefresh = Array.from(watchedOperations.values()).find((o) => getOperationName(o.query) === refreshOnly.operation) + + if (!toRefresh) { + awaitingMount[refreshOnly.operation] = refreshOnly + } else { + reexecuteOperation(toRefresh, fieldHeader) + } + } else { + watchedOperations.forEach((op) => { + reexecuteOperation(op) + }) + } + }) + + const processIncomingOperation = (op: Operation) => { + if (op.kind === 'teardown' && observedOperations.has(op.key)) { + observedOperations.delete(op.key) + watchedOperations.delete(op.key) + } + } + + const processResultOperation = (op: OperationResult) => { + if (op.operation.kind === 'query' && !observedOperations.has(op.operation.key)) { + observedOperations.set(op.operation.key, 1) + watchedOperations.set(op.operation.key, op.operation) + const name = getOperationName(op.operation.query) + + if (name && awaitingMount[name]) { + const awaiting = awaitingMount[name] + + delete awaitingMount[name] + reexecuteOperation(op.operation, `${awaiting.operation}.${awaiting.field}`) + } + } + } + + return (ops$) => { + if (typeof window === 'undefined') { + return forward(ops$) + } + + return pipe(forward(pipe(ops$, tap(processIncomingOperation))), tap(processResultOperation)) + } + } +} + +function getOperationName (query: DocumentNode): string | undefined { + return getPrimaryOperation(query)?.name?.value +} + +function getPrimaryOperation (query: DocumentNode): OperationDefinitionNode | undefined { + return query.definitions.find(isOperationDefinitionNode) +} + +function isOperationDefinitionNode (node: DefinitionNode): node is OperationDefinitionNode { + return node.kind === 'OperationDefinition' +} diff --git a/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts b/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts new file mode 100644 index 0000000000..82bd58e0ac --- /dev/null +++ b/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts @@ -0,0 +1,32 @@ +import _ from 'lodash' +import type { Socket } from '@packages/socket/lib/browser' +import type { ClientOptions } from '@urql/core' + +export const urqlFetchSocketAdapter = (io: Socket): ClientOptions['fetch'] => { + return (url, fetchOptions = {}) => { + return new Promise((resolve, reject) => { + // Handle aborted requests + if (fetchOptions.signal) { + fetchOptions.signal.onabort = () => { + reject(new DOMException('Aborted', 'AbortError')) + } + + if (fetchOptions.signal.aborted) { + return reject(new DOMException('Aborted', 'AbortError')) + } + } + + const uid = _.uniqueId('gql') + + // An ad-hoc version of the "Request" + io.emit(`graphql:request`, uid, fetchOptions.body, (payload) => { + resolve(new Response(JSON.stringify(payload), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + })) + }) + }) + } +} diff --git a/packages/frontend-shared/src/index.ts b/packages/frontend-shared/src/index.ts new file mode 100644 index 0000000000..87457572d6 --- /dev/null +++ b/packages/frontend-shared/src/index.ts @@ -0,0 +1 @@ +export * from './graphql/urqlClient' diff --git a/packages/frontend-shared/src/locales/en-US.json b/packages/frontend-shared/src/locales/en-US.json new file mode 100644 index 0000000000..a69afa4323 --- /dev/null +++ b/packages/frontend-shared/src/locales/en-US.json @@ -0,0 +1,672 @@ +{ + "links": { + "learnMore": "Learn more.", + "needHelp": "Need help" + }, + "components": { + "modal": { + "dismiss": "Dismiss" + }, + "fileSearch": { + "noMatchesForExtension": "No files found when searching for the file extension", + "noMatchesForFileName": "", + "byFilenameInput": "Search by filename...", + "byExtensionInput": "Extensions to include e.g. *.tsx, *.vue", + "matchesIndicatorEmptyFileSearch": "No Matches | 1 Match | { denominator } Matches", + "matchesIndicator": "No Matches | {numerator} of {denominator} Matches | {numerator} of {denominator} Matches" + }, + "button": { + "cancel": "Cancel", + "back": "Back" + }, + "loading": { + "config": { + "title": "Initializing Config...", + "description": "Please wait while we load your project and find browsers installed on your system" + } + }, + "select": { + "placeholder": "Choose an option..." + }, + "alert": { + "dismissAriaLabel": "Dismiss" + }, + "specPattern": { + "matches": "{0} Matches" + }, + "specPatternModal": { + "title": "Spec pattern settings" + } + }, + "clipboard": { + "copy": "Copy", + "copied": "Copied!" + }, + "actions": { + "close": "Close" + }, + "file": { + "edit": "Edit", + "git": { + "modified": "Modified", + "created": "Created", + "unmodified": "Modified" + } + }, + "status": { + "enabled": "Enabled", + "disabled": "Disabled" + }, + "createSpec": { + "newSpec": "New Spec", + "createSpec": "Create Spec", + "done": "Done!", + "updateSpecPattern": "Update Spec Pattern", + "newSpecModalTitle": "Create a new spec", + "successPage": { + "header": "Great! The spec was successfully added", + "runSpecButton": "Okay, run the spec", + "createAnotherSpecButton": "Create another spec" + }, + "page": { + "defaultPatternNoSpecs": { + "title": "Create your first spec", + "component": { + "description": "Since this project looks new, we recommend that you get started by creating a spec for one of your components." + }, + "e2e": { + "description": "Since this project looks new, we recommend that you use the specs and tests that we've written for you to get started." + } + }, + "customPatternNoSpecs": { + "title": "No Specs Found", + "description": "We couldn't find any files matching the following spec patterns. You may need to move your specs or update your {0} to find them." + } + }, + "noSpecsMessage": "If you feel that you're seeing this screen in error, and there should be specs listed here, you likely need to update the spec pattern.", + "viewSpecPatternButton": "View spec pattern", + "e2e": { + "importFromScaffold": { + "header": "Scaffold example specs", + "description": "We'll generate several example specs to help guide you on how to write tests in Cypress.", + "specsAddedHeader": "Great! We added the following files to your project:", + "specsAddedButton": "Okay, I got it!", + "specsAddingHeader": "Adding Specs..." + }, + "importEmptySpec": { + "header": "Create new empty spec", + "description": "We'll generate an empty spec file which can be used to start testing your application.", + "chooseFilenameHeader": "Enter the path for your new spec", + "inputPlaceholder": "Enter a relative path...", + "invalidSpecWarning": "This path is invalid because it doesn't match the following ", + "specExtensionWarning": "We recommend naming your spec to match the following pattern: " + } + }, + "component": { + "importFromComponent": { + "header": "Create from component", + "description": "We'll generate an empty spec file which can be used to import and test any component in this project.", + "chooseAComponentHeader": "Choose a component" + }, + "importEmptySpec": { + "header": "Create a new spec", + "description": "We'll generate an empty spec file to start testing components.", + "invalidComponentWarning": "We couldn't generate a valid path matching your custom " + } + } + }, + "specPage": { + "pageTitle": "Specs", + "newSpecButton": "New Spec", + "searchPlaceholder": "Search Specs", + "componentSpecsHeader": "Component Specs", + "e2eSpecsHeader": "E2E Specs", + "gitStatusHeader": "Git Status", + "rows": { + "gitInfoWithAuthor": "{fileState} {timeAgo} by {author}", + "gitInfo": "{fileState} {timeAgo}" + }, + "noResultsMessage": "No specs matched your search:", + "noSpecErrorTitle": "Spec not found", + "noSpecErrorIntro": "There is no spec matching the following location:", + "noSpecErrorExplainer": "It is possible that the file has been moved or deleted. Please choose from the list of specs below." + }, + "noResults": { + "defaultMessage": "No results matched your search:", + "clearSearch": "Clear Search" + }, + "sideBar": { + "keyboardShortcuts": { + "title": "Keyboard Shortcuts", + "rerun": "Re-run tests", + "stop": "Stop tests", + "toggle": "Toggle specs list" + } + }, + "topNav": { + "released": "Released", + "version": "Version", + "installed": "Installed", + "latest": "Latest", + "seeAllReleases": "See all releases", + "runningOldVersion": "You're currently running an old version of Cypress. Update to the latest version for the best experience.", + "docsMenu": { + "docsHeading": "Docs", + "gettingStartedTitle": "Getting Started", + "firstTest": "Write your first test", + "testingApp": "Testing your app", + "organizingTests": "Organizing Tests", + "referencesTitle": "References", + "bestPractices": "Best Practices", + "configuration": "Configuration", + "api": "API", + "ciTitle": "Run in CI/CD", + "ciSetup": "Set up CI", + "fasterTests": "Run tests faster", + "prompts": { + "ci1": { + "title": "Configure CI", + "description": "Optimize your tests in CI by following these guides.", + "seeOtherGuides": "See Other Guides", + "intro": "Introduction to CI", + "learnTheBasics": "Learn the basics of running Cypress in CI." + }, + "orchestration1": { + "title": "Run tests faster in CI", + "parallelTime": "5 mins", + "noParallelTime": "12 mins", + "withParallelization": "with Parallelization", + "withoutParallelization": "without Parallelization", + "intro": "With Smart Orchestration, you'll be able to:", + "bullet1": "Run spec files in parallel", + "bullet2": "Prioritize failed specs to run first", + "bullet3": "Cancel CI runs on test failure", + "learnMore": "Learn more" + } + } + }, + "login": { + "bodyInitial": "Logging in gives you access to the {0}. You can set up projects to be recorded and see test data from your project.", + "bodySuccess": "You are now logged in as {0}.", + "bodyError": "An error occurred while attempting to log in:", + "bodyBrowserError": "The browser could not be opened.", + "bodyBrowserErrorDetails": "Cypress was unable to open your installed browser. To continue logging in, please paste this URL into your web browser:", + "cloud": "Cypress Dashboard Service", + "titleInitial": "Log in to Cypress", + "titleSuccess": "Login Successful", + "titleFailed": "Login Failed", + "titleBrowserError": "Browser Error", + "actionLogin": "Log In", + "profileMenuLabel": "Profile and Log Out", + "actionLogout": "Log Out", + "actionContinue": "Continue", + "actionOpening": "Opening Browser", + "actionWaiting": "Waiting for you to log in", + "actionTryAgain": "Try again", + "actionCancel": "Cancel" + }, + "updateCypress": { + "title": "Upgrade to Cypress", + "currentlyRunning": "You are currently running Version {0} of Cypress. ", + "pasteToUpgradeProject": "To upgrade to the latest version for your project, first {0}, then paste the command below into your terminal:", + "pasteToUpgradeGlobal": "To upgrade to the latest version, first {0}, then paste the command below into your terminal:", + "rememberToCloseInsert": "close this app" + }, + "upgradeText": "Upgrade", + "global": { + "projects": "Projects" + } + }, + "launchpadErrors": { + "generic": { + "header": "Something went wrong", + "message": "It looks like there's some issues that need to be resolved before we continue. Please confirm that everything looks correct in your {0} file.", + "readTheDocsButton": "Read the docs", + "retryButton": "Try again", + "stackTraceLabel": "Stack Trace" + }, + "noInternet": { + "header": "You have no internet connection", + "message": "Check your internet connection to pull the latest data from the dashboard." + } + }, + "setupPage": { + "projectSetup": { + "frameworkLabel": "Front-end Framework", + "frameworkPlaceholder": "Pick a framework", + "bundlerLabel": "Bundler", + "bundlerLabelDescription": "(Dev Server)", + "bundlerPlaceholder": "Pick a bundler", + "languageLabel": "Language", + "configFileLanguageLabel": "Cypress Config File", + "detected": "(detected)" + }, + "install": { + "startButton": "Install", + "waitForInstall": "Waiting for you to install the dependencies...", + "installed": "installed", + "pendingInstall": "pending installation" + }, + "step": { + "continue": "Continue", + "next": "Next Step", + "back": "Back", + "skip": "Skip" + }, + "configFile": { + "createManually": "Create file manually", + "skippedLabel": "Skipped", + "changesRequiredLabel": "Changes Required", + "changesRequiredBadge": "Changes required", + "changesRequiredDescription": "Please merge the code below with your existing {0}" + }, + "testingCard": { + "configured": "Configured", + "notConfigured": "Not Configured", + "running": "Running", + "chooseABrowser": "Choose a Browser", + "reconfigure": "Reconfigure" + } + }, + "globalPage": { + "empty": { + "title": "Add Project", + "helper": "Get started by adding your first project below.", + "dropText": "Drag your project directory here or {0}", + "browseManually": "browse manually." + }, + "settings": "Settings", + "saveChanges": "Save Changes", + "cancel": "Cancel", + "externalEditorPreferences": "External Editor Preferences", + "externalEditorPreferencesDescription1": "Select your preference for opening files on your system.", + "externalEditorPreferencesDescription2": "You can change this later in the {0} page.", + "recentProjectsHeader": "Recent Projects", + "searchPlaceholder": "Search projects", + "addProjectButton": "Add Project", + "projectActions": "Project Actions", + "removeProject": "Remove Project", + "openInIDE": "Open In IDE", + "openInFinder": "Open In Finder", + "noResultsMessage": "No projects matched your search:" + }, + "welcomePage": { + "review": "Review the differences between each testing type", + "codeExample": "Code Example", + "compareTypes": { + "content": { + "e2eTitle": "End-to-end Tests", + "e2eBullet1": "Visit URLs via", + "e2eBullet2": "Test flows and functionality across multiple pages.", + "e2eBullet3": "Ideal for testing integrated flows in CD workflows.", + "componentTitle": "Component Tests", + "ctBullet1": "Import components via", + "ctBullet2": "Test individual components of a design system in isolation", + "ctBullet3": "Ideal for testing isolated flows and components in CI" + }, + "modalTitle": "Key Differences" + }, + "title": "Welcome to Cypress!" + }, + "settingsPage": { + "config": { + "title": "Resolved Configuration", + "description": "Since the options in the {0} can be set dynamically by your development environment, please refer to the legend below to understand how the configuration options are resolved.", + "legend": { + "env": { + "label": "env", + "description": "Set from environment variables" + }, + "default": { + "label": "default", + "description": "Default values" + }, + "dynamic": { + "label": "dynamic", + "description": "Set by the {0} function" + }, + "cli": { + "label": "cli", + "description": "Set from CLI arguments" + }, + "config": { + "label": "config", + "description": "Set from {0}" + } + } + }, + "proxy": { + "title": "Proxy Settings", + "description": "Cypress auto-detected the following proxy settings from your operating system.", + "bypassList": "Proxy Bypass List", + "proxyServer": "Proxy Server" + }, + "editor": { + "title": "External Editor", + "description": "External editor to use for editing code opened when using Cypress.", + "noEditorSelectedPlaceholder": "Choose your editor...", + "customPathPlaceholder": "/path/to/editor" + }, + "projectId": { + "title": "Project ID", + "description": "The Project ID configured for this project inside of Cypress Dashboard. {0}" + }, + "specPattern": { + "title": "Spec Patterns", + "description": "The globs pointing Cypress App to your spec files configured for this project. {0}" + }, + "recordKey": { + "title": "Record Key", + "description": "The Record Key configured for this project inside of Cypress Dashboard. {0}", + "manageKeys": "Manage Keys", + "errorEmpty": "You do not have permission to record on this project", + "errorEmptyButton": "Request record rights", + "errorAccess": "You do not have permission to view this project", + "errorAccessPending": "Your request for access to this project is pending approval", + "errorAccessButton": "Request access", + "errorNotFound": "Project not found", + "errorNotFoundButton": "Connect it again", + "errorNotLoggedIn": "You are not connected to the Cypress Dashboard", + "errorNotLoggedInButton": "Log in to Cypress Dashboard" + }, + "project": { + "title": "Project Settings", + "description": "Review the configuration settings currently in use for this project." + }, + "cloud": { + "title": "Dashboard Settings", + "description": "Review the configuration settings for recording to the Cypress Dashboard." + }, + "experiments": { + "title": "Experiments", + "description": "If you'd like to try out new features that we're working on, you can enable beta features for your project by turning on the experimental features you'd like to try. {0}", + "experimentalFetchPolyfill": { + "name": "Fetch Polyfill", + "description": "Automatically replaces `window.fetch` with a polyfill that Cypress can spy on and stub. Note: `experimentalFetchPolyfill` has been deprecated in Cypress 6.0.0 and will be removed in a future release. Consider using [`cy.intercept()`](https://on.cypress.io/intercept) to intercept `fetch` requests instead." + }, + "experimentalInteractiveRunEvents": { + "name": "Interactive Run Events", + "description": "Allows listening to the [`before:run`](https://on.cypress.io/before-run), [`after:run`](https://on.cypress.io/after-run), [`before:spec`](https://on.cypress.io/before-spec), and [`after:spec`](https://on.cypress.io/after-spec) events in plugins during interactive mode." + }, + "experimentalSessionSupport": { + "name": "Session", + "description": "Enable use of [`cy.session()`](https://on.cypress.io/session) and new behavior to handle caching and restoring cookies, localStorage, and sessionStorage." + }, + "experimentalSourceRewriting": { + "name": "Source Rewriting", + "description": "Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm. See [#5273](https://github.com/cypress-io/cypress/issues/5273) for details." + } + }, + "device": { + "title": "Device Settings", + "description": "Review the configuration settings currently in use for this device." + }, + "testingPreferences": { + "title": "Testing Preferences", + "description": "Configure your testing environment with these flags", + "autoScrollingEnabled": { + "title": "Auto Scrolling Enabled", + "description": "Scroll behavior when running tests." + } + }, + "footer": { + "text": "You can reconfigure the settings for this project if you're experiencing issues with your Cypress configuration.", + "button": "Reconfigure Project" + } + }, + "runs": { + "connect": { + "title": "View your recorded runs from the Cypress Dashboard", + "smartText": "Scale your test runs with built-in smart orchestration.", + "debugText": "Debug tests that fail in CI with visual feedback.", + "chartText": "Keep your tests in tip-top shape with powerful analytics.", + "buttonUser": "Log in to the Cypress Dashboard", + "buttonProject": "Connect your project to the Cypress Dashboard", + "modal": { + "title": "Connect Project", + "cancel": "Cancel", + "createOrg": { + "description": "You need to create an organization in the Cypress Dashboard to continue.", + "button": "Create Organization", + "waitingButton": "Waiting for you to create an organization...", + "refreshButton": "Refresh Organizations List" + }, + "selectProject": { + "organization": "Organization", + "noOrganizationSelectedError": "required when creating a new project", + "manageOrgs": "Manage organizations", + "project": "Project", + "projectName": "Project Name", + "projectNameDisclaimer": "(You can change this later)", + "createNewProject": "Create new", + "chooseExistingProject": "Choose an existing project", + "newProjectAccess": "Project Access", + "privateLabel": "Private", + "privateDescription": "Only invited users can view recorded test results.", + "publicLabel": "Public", + "publicDescription": "Anyone can view recorded test results.", + "connectProject": "Connect project", + "createProject": "Create project", + "placeholderOrganizations": "Pick an organization", + "placeholderProjects": "Pick a project", + "placeholderProjectsPending": "Pick an organization first" + }, + "connectManually": { + "title": "Connect Project Manually", + "warning": "We couldn't add the projectId to your cypress.config.js file automatically.", + "mainMessage": "Manually add the {projectId} to the root of the config object in your {configFile} file.", + "waitingButton": "Waiting for you to add the projectId..." + } + } + }, + "connectSuccessAlert": { + "title": "This project is now connected to the Cypress Dashboard!", + "item1": "We automatically added the {projectId} to your {configFile} file.", + "item2": "Please ensure that your {0} file is checked into source control." + }, + "empty": { + "title": "Record your first run to the Cypress Dashboard", + "description": "Run the command below in your local development terminal or in CI." + }, + "results": { + "skipped": "skipped", + "pending": "pending", + "passed": "passed", + "failed": "failed" + }, + "errors": { + "notfound": { + "title": "Couldn't find your project", + "description": "We were unable to find an existing project matching the {0} set in your Cypress config file. You can reconnect with an existing project or create a new project.", + "button": "Reconnect your project" + }, + "unauthorized": { + "title": "Request access to view the recorded runs", + "description": "This is a private project that you do not current have access to. Please request access from the project owner in order to view the list of runs.", + "button": "Request Access" + }, + "unauthorizedRequested": { + "title": "Your access request for this project has been sent.", + "description": "The owner of this project has been notified of your request. We'll notify you via email when your access request has been granted.", + "button": "Request Sent" + } + } + }, + "testingType": { + "modalTitle": "Choose a testing type", + "e2e": { + "name": "E2E Testing", + "description": "Build and test the entire experience of your application from end-to-end to ensure each flow matches your expectations." + }, + "component": { + "name": "Component Testing", + "description": "Build and test your components from your design system in isolation in order to ensure each state matches your expectations." + } + }, + "migration": { + "before": "Before", + "after": "After", + "heresWhy": "here's why:", + "renameAuto": { + "title": "We'll automatically rename your specs in this step", + "changeButton": "change", + "changedSpecFolder": "We've changed the default spec folder from:", + "changedSpecExt": "We've changed the default spec file extension from:", + "changedSpecPatternExplain": "We've made the default spec file extension to {0} in order to avoid conflicts with any existing testing frameworks.", + "optedOutMessage": "You've opted not to rename your spec file extension", + "folderRenameMessage": "You've opted not to rename your spec file extension, we're going to rename the folder", + "modals": { + "title": "Change the existing spec file extension", + "step1": { + "warning": "We recommend using the default extension to avoid inconsistencies, framework conflicts, and confusion with your team.", + "line1": "Cypress now supports the ability to create new spec files from within the UI for both E2E and component specs.", + "line2": "All new spec files created within Cypress will use the default pattern of: ", + "line3": "We want to rename your existing specs so that they have a consistent filename pattern for both E2E and component testing.", + "line4": "All documentation and example code will be using: ", + "line5": "We've changed the placement of component specs to be next to their source files (e.g. src/Button.jsx and src/Button.cy.jsx)", + "line6": "The new default pattern of {0} prevents targeting conflicts with other testing frameworks. (e.g. Jest)", + "buttonProceed": "I still want to change the spec file extension", + "buttonCancel": "Cancel, keep the default extension" + }, + "step2": { + "warning": "You may need to change your specPattern later if you don't use the recommended filename extension.", + "label": "Choose from the following filename patterns:", + "option1": "{0} (Recommended)", + "option2": "Don't rename anything โ€” keep what I have.", + "option3": "Rename folder only.", + "buttonSave": "Save Changes", + "buttonCancel": "Cancel" + } + } + }, + "renameManual": { + "title": "We need you to move your component specs manually", + "componentFolderRemoved": "We've removed the {0} options from the Cypress config.", + "addedSpecPattern": "We've added a new {0} option in the Cypress config that tells us where to find your component specs.", + "cannotAuto": "We can't automatically migrate your existing component spec files. We recommend that you move the following component spec files next to your source component files (e.g. {0})", + "ifSkipNote": "If you skip this step, Cypress will still be able to find them, but any new specs that you create will automatically be created next to your component files." + }, + "renameSupport": { + "title": "We'll automatically rename your existing E2E support file in this step", + "serveDifferentTypes": "We now serve different support files for E2E and component testing.", + "changedSupportFile": "We've renamed the E2E support file from:" + }, + "configFile": { + "title": "We need to migrate to the new Cypress configuration file", + "changedDefault": "We've changed the default Cypress config file from:", + "customOptions": "We've set a custom {specPattern} option based on your {options}.", + "willConvert": "We'll automatically create a new {jsFile} file and seed it with your options from your existing {jsonFile}." + }, + "setupComponent": { + "title": "You need to reconfigure Cypress for component testing", + "line1": "We've detected that you are currently using the experimental version of component testing.", + "line2": "Your existing configuration is no longer compatible with new component testing configuration options.", + "line3": "In a previous step, we renamed your component specs, but can't automatically migrate your existing component testing configuration.", + "line4": "In the next screen, you'll be able to reconfigure component testing in a new guided configuration wizard." + }, + "wizard": { + "title": "Migration Helper", + "description": "Complete the steps below to migrate your project to Cypress 10", + "step1": { + "title": "Rename existing specs", + "description": "In this step, we'll automatically rename and move your existing spec files.", + "button": "Rename these specs for me", + "buttonSkip": "Skip renaming specs", + "buttonRenameFolder": "Rename the folder for me" + }, + "step2": { + "title": "Move your existing component specs", + "description": "In this step, you'll manually move your existing component specs to their new default location.", + "buttonWait": "Waiting for you to move your component specs...", + "buttonDone": "Continue to next step", + "button": "I'll do this later" + }, + "step3": { + "title": "Rename the Cypress support file", + "description": "In this step, we'll automatically rename your existing support file.", + "button": "Rename the support file for me" + }, + "step4": { + "title": "Migrate to the new Cypress configuration file", + "description": "In this step, we'll automatically migrate your existing cypress configuration to the new Cypress configuration file.", + "button": "Migrate the configuration for me" + }, + "step5": { + "title": "Reconfigure component testing", + "description": "In this step, we'll explain how you will reconfigure Cypress for component testing.", + "button": "Finish migration and continue" + } + } + }, + "setupWizard": { + "selectFramework": { + "title": "Project Setup", + "description": "Confirm the front-end framework and bundler used in your project." + }, + "installDependencies": { + "title": "Install Dev Dependencies", + "description": "Paste the command below into your terminal to install the required packages." + }, + "configFiles": { + "title": "Configuration Files", + "description": "We added the following files to your project." + }, + "chooseBrowser": { + "title": "Choose a Browser", + "description": "Choose your preferred browser for {testingType} testing." + } + }, + "e2eProjectSetup": { + "title": "Project Setup", + "description": "Confirm your project's preferred language." + }, + "openBrowser": { + "startComponent": "Start Component Testing in {browser}", + "startE2E": "Start E2E Testing in {browser}", + "openingComponent": "Opening Component Testing in {browser}", + "openingE2E": "Opening E2E Testing in {browser}", + "running": "Running {browser}", + "focus": "Focus", + "close": "Close", + "switchTestingType": "Switch testing type" + }, + "runner": { + "header": { + "reviewDocs": "Review the docs", + "troubleRendering": "if you're having trouble rendering your components properly." + }, + "snapshot": { + "toggleHighlights": "Toggle highlights", + "highlightsLabel": "Highlights", + "testsRunningError": "Cannot show Snapshot while tests are running", + "snapshotMissingError": "The snapshot is missing. Displaying current state of the DOM.", + "defaultTitle": "DOM Snapshot", + "pinnedTitle": "Pinned", + "studioActiveError": "Cannot show Snapshot while creating commands in Studio" + }, + "selectorPlayground": { + "matches": "No Matches | {n} Match | {n} Matches", + "copyTooltip": "Copied to clipboard", + "printTooltip": "Printed to console", + "invalidSelector": "Invalid", + "selectorMethodsLabel": "Selector Methods" + }, + "automation": { + "disconnected": { + "title": "The Cypress extension has disconnected.", + "description": "Cypress cannot run tests without this extension.", + "reload": "Reload the browser" + }, + "missing": { + "title": "The Cypress extension is missing.", + "description": "Cypress cannot run tests without this extension. Please choose another browser." + }, + "shared": { + "link": "Read more about browser management" + } + } + }, + "warnings": { + "retry": "Try again" + } +} diff --git a/packages/frontend-shared/src/locales/i18n.ts b/packages/frontend-shared/src/locales/i18n.ts new file mode 100644 index 0000000000..abd240ca41 --- /dev/null +++ b/packages/frontend-shared/src/locales/i18n.ts @@ -0,0 +1,29 @@ +import { + useI18n as _useI18n, + createI18n as _createI18n, +} from 'vue-i18n' + +import type enUS from './en-US.json' +// Imports a special compiled messages object +import compiledMessages from '@intlify/vite-plugin-vue-i18n/messages' + +// The raw strings for the default language (en) used for testing +import rawJsonMessages from './en-US.json?raw' + +export type MessageSchema = typeof enUS + +export const defaultMessages: MessageSchema = JSON.parse(rawJsonMessages) + +export const VueI18n = createI18n() + +export function createI18n (opts = {}) { + return _createI18n({ + locale: 'en-US', + messages: compiledMessages, + ...opts, + }) +} + +export function useI18n () { + return _useI18n<{ message: MessageSchema }>({ useScope: 'global' }) +} diff --git a/packages/frontend-shared/src/locales/schema.ts b/packages/frontend-shared/src/locales/schema.ts new file mode 100644 index 0000000000..08ac6908f6 --- /dev/null +++ b/packages/frontend-shared/src/locales/schema.ts @@ -0,0 +1,8 @@ +/** + * define the resource schema + */ + +import type enUS from './en-US.json' + +// define the locale message schema as master +export type MessageSchema = typeof enUS diff --git a/packages/frontend-shared/src/public/fonts/FiraCode-VF.woff2 b/packages/frontend-shared/src/public/fonts/FiraCode-VF.woff2 new file mode 100644 index 0000000000..1b9482629e Binary files /dev/null and b/packages/frontend-shared/src/public/fonts/FiraCode-VF.woff2 differ diff --git a/packages/frontend-shared/src/public/shiki/languages/css.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/css.tmLanguage.json new file mode 100644 index 0000000000..8fa551e959 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/css.tmLanguage.json @@ -0,0 +1,1865 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-css/blob/master/grammars/css.cson", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/atom/language-css/commit/033087e8caa1b87ca91ee5b211de118b6b3c311d", + "name": "css", + "scopeName": "source.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#combinators" + }, + { + "include": "#selector" + }, + { + "include": "#at-rules" + }, + { + "include": "#rule-list" + } + ], + "repository": { + "at-rules": { + "patterns": [ + { + "begin": "\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))", + "end": ";|(?=$)", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.charset.css", + "patterns": [ + { + "captures": { + "1": { + "name": "invalid.illegal.not-lowercase.charset.css" + }, + "2": { + "name": "invalid.illegal.leading-whitespace.charset.css" + }, + "3": { + "name": "invalid.illegal.no-whitespace.charset.css" + }, + "4": { + "name": "invalid.illegal.whitespace.charset.css" + }, + "5": { + "name": "invalid.illegal.not-double-quoted.charset.css" + }, + "6": { + "name": "invalid.illegal.unclosed-string.charset.css" + }, + "7": { + "name": "invalid.illegal.unexpected-characters.charset.css" + } + }, + "match": "(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^\";]+) # Not double-quoted\n|\n(\"[^\"]+$) # Unclosed quote\n|\n(?<=\") # After charset name\n([^;]+) # Unexpected junk instead of semicolon" + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.charset.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "((@)charset)(?=\\s)" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.css" + } + }, + "end": "\"|$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.css" + } + }, + "name": "string.quoted.double.css", + "patterns": [ + { + "begin": "(?:\\G|^)(?=(?:[^\"])+$)", + "end": "$", + "name": "invalid.illegal.unclosed.string.css" + } + ] + } + ] + }, + { + "begin": "(?i)((@)import)(?:\\s+|$|(?=['\"]|/\\*))", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.import.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.import.css", + "patterns": [ + { + "begin": "\\G\\s*(?=/\\*)", + "end": "(?<=\\*/)\\s*", + "patterns": [ + { + "include": "#comment-block" + } + ] + }, + { + "include": "#string" + }, + { + "include": "#url" + }, + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "(?i)((@)font-face)(?=\\s*|{|/\\*|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.font-face.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?!\\G)", + "name": "meta.at-rule.font-face.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(@)page(?=[\\s:{]|/\\*|$)", + "captures": { + "0": { + "name": "keyword.control.at-rule.page.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*($|[:{;]))", + "name": "meta.at-rule.page.css", + "patterns": [ + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(?=@media(\\s|\\(|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)media", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.media.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.media.header.css", + "patterns": [ + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.media.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.media.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.media.body.css", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@counter-style([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)counter-style", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.counter-style.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*{)", + "name": "meta.at-rule.counter-style.header.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "captures": { + "0": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*", + "name": "variable.parameter.style-name.css" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.property-list.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.property-list.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.counter-style.body.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list-innards" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@document([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)document", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.document.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.document.header.css", + "patterns": [ + { + "begin": "(?i)(?>>", + "name": "invalid.deprecated.combinator.css" + }, + { + "match": ">>|>|\\+|~", + "name": "keyword.operator.combinator.css" + } + ] + }, + "commas": { + "match": ",", + "name": "punctuation.separator.list.comma.css" + }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.css" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.css" + } + }, + "name": "comment.block.css" + }, + "escapes": { + "patterns": [ + { + "match": "\\\\[0-9a-fA-F]{1,6}", + "name": "constant.character.escape.codepoint.css" + }, + { + "begin": "\\\\$\\s*", + "end": "^(?<:=]|\\)|/\\*) # Terminates cleanly" + }, + "media-feature-keywords": { + "match": "(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n | hover\n)\n(?=\\s|\\)|$)", + "name": "support.constant.property-value.css" + }, + "media-query": { + "begin": "\\G", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#media-types" + }, + { + "match": "(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)", + "name": "keyword.operator.logical.$1.media.css" + }, + { + "match": "(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)", + "name": "keyword.operator.logical.and.media.css" + }, + { + "match": ",(?:(?:\\s*,)+|(?=\\s*[;){]))", + "name": "invalid.illegal.comma.css" + }, + { + "include": "#commas" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.css" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.css" + } + }, + "patterns": [ + { + "include": "#media-features" + }, + { + "include": "#media-feature-keywords" + }, + { + "match": ":", + "name": "punctuation.separator.key-value.css" + }, + { + "match": ">=|<=|=|<|>", + "name": "keyword.operator.comparison.css" + }, + { + "captures": { + "1": { + "name": "constant.numeric.css" + }, + "2": { + "name": "keyword.operator.arithmetic.css" + }, + "3": { + "name": "constant.numeric.css" + } + }, + "match": "(\\d+)\\s*(/)\\s*(\\d+)", + "name": "meta.ratio.css" + }, + { + "include": "#numeric-values" + }, + { + "include": "#comment-block" + } + ] + } + ] + }, + "media-query-list": { + "begin": "(?=\\s*[^{;])", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#media-query" + } + ] + }, + "media-types": { + "captures": { + "1": { + "name": "support.constant.media.css" + }, + "2": { + "name": "invalid.deprecated.constant.media.css" + } + }, + "match": "(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)" + }, + "numeric-values": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.constant.css" + } + }, + "match": "(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b", + "name": "constant.other.color.rgb-value.hex.css" + }, + { + "captures": { + "1": { + "name": "keyword.other.unit.percentage.css" + }, + "2": { + "name": "keyword.other.unit.${2:/downcase}.css" + } + }, + "match": "(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!\"'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.class.css" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)", + "name": "entity.other.attribute-name.id.css" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.entity.begin.bracket.square.css" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.entity.end.bracket.square.css" + } + }, + "name": "meta.attribute-selector.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#string" + }, + { + "captures": { + "1": { + "name": "storage.modifier.ignore-case.css" + } + }, + "match": "(?<=[\"'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)" + }, + { + "captures": { + "1": { + "name": "string.unquoted.attribute-value.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\\"'\\s\\]]|\\\\.)+)" + }, + { + "include": "#escapes" + }, + { + "match": "[~|^$*]?=", + "name": "keyword.operator.pattern.css" + }, + { + "match": "\\|", + "name": "punctuation.separator.css" + }, + { + "captures": { + "1": { + "name": "entity.other.namespace-prefix.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)" + }, + { + "captures": { + "1": { + "name": "entity.other.attribute-name.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)" + } + ] + }, + { + "include": "#pseudo-classes" + }, + { + "include": "#pseudo-elements" + }, + { + "include": "#functional-pseudo-classes" + }, + { + "match": "(?x) (?\\s,.\\#|){\\[]|/\\*|:[^\\s]|$)", + "name": "entity.name.tag.css" + }, + "unicode-range": { + "captures": { + "0": { + "name": "constant.other.unicode-range.css" + }, + "1": { + "name": "punctuation.separator.dash.unicode-range.css" + } + }, + "match": "(?)", + "patterns": [ + { + "begin": "(?=[^\\s=<>`/]|/(?!>))", + "end": "(?!\\G)", + "name": "meta.embedded.line.css", + "patterns": [ + { + "captures": { + "0": { + "name": "source.css" + } + }, + "match": "([^\\s\"'=<>`/]|/(?!>))+", + "name": "string.unquoted.html" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "contentName": "source.css", + "end": "(\")", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + }, + "1": { + "name": "source.css-ignored-vscode" + } + }, + "name": "string.quoted.double.html", + "patterns": [ + { + "include": "#entities" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "contentName": "source.css", + "end": "(')", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + }, + "1": { + "name": "source.css-ignored-vscode" + } + }, + "name": "string.quoted.single.html", + "patterns": [ + { + "include": "#entities" + } + ] + } + ] + }, + { + "match": "=", + "name": "invalid.illegal.unexpected-equals-sign.html" + } + ] + } + ] + }, + { + "begin": "on(s(croll|t(orage|alled)|u(spend|bmit)|e(curitypolicyviolation|ek(ing|ed)|lect))|hashchange|c(hange|o(ntextmenu|py)|u(t|echange)|l(ick|ose)|an(cel|play(through)?))|t(imeupdate|oggle)|in(put|valid)|o(nline|ffline)|d(urationchange|r(op|ag(start|over|e(n(ter|d)|xit)|leave)?)|blclick)|un(handledrejection|load)|p(opstate|lay(ing)?|a(ste|use|ge(show|hide))|rogress)|e(nded|rror|mptied)|volumechange|key(down|up|press)|focus|w(heel|aiting)|l(oad(start|e(nd|d(data|metadata)))?|anguagechange)|a(uxclick|fterprint|bort)|r(e(s(ize|et)|jectionhandled)|atechange)|m(ouse(o(ut|ver)|down|up|enter|leave|move)|essage(error)?)|b(efore(unload|print)|lur))(?![\\w:-])", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "comment": "HTML5 attributes, event handlers", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.event-handler.$1.html", + "patterns": [ + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "punctuation.separator.key-value.html" + } + }, + "end": "(?<=[^\\s=])(?!\\s*=)|(?=/?>)", + "patterns": [ + { + "begin": "(?=[^\\s=<>`/]|/(?!>))", + "end": "(?!\\G)", + "name": "meta.embedded.line.js", + "patterns": [ + { + "captures": { + "0": { + "name": "source.js" + }, + "1": { + "patterns": [ + { + "include": "source.js" + } + ] + } + }, + "match": "(([^\\s\"'=<>`/]|/(?!>))+)", + "name": "string.unquoted.html" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "contentName": "source.js", + "end": "(\")", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + }, + "1": { + "name": "source.js-ignored-vscode" + } + }, + "name": "string.quoted.double.html", + "patterns": [ + { + "captures": { + "0": { + "patterns": [ + { + "include": "source.js" + } + ] + } + }, + "match": "([^\\n\"/]|/(?![/*]))+" + }, + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "(?=\")|\\n", + "name": "comment.line.double-slash.js" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.js" + } + }, + "end": "(?=\")|\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.js" + } + }, + "name": "comment.block.js" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "contentName": "source.js", + "end": "(')", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + }, + "1": { + "name": "source.js-ignored-vscode" + } + }, + "name": "string.quoted.single.html", + "patterns": [ + { + "captures": { + "0": { + "patterns": [ + { + "include": "source.js" + } + ] + } + }, + "match": "([^\\n'/]|/(?![/*]))+" + }, + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "(?=')|\\n", + "name": "comment.line.double-slash.js" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.js" + } + }, + "end": "(?=')|\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.js" + } + }, + "name": "comment.block.js" + } + ] + } + ] + }, + { + "match": "=", + "name": "invalid.illegal.unexpected-equals-sign.html" + } + ] + } + ] + }, + { + "begin": "(data-[a-z\\-]+)(?![\\w:-])", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "comment": "HTML5 attributes, data-*", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.data-x.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "begin": "(align|bgcolor|border)(?![\\w:-])", + "beginCaptures": { + "0": { + "name": "invalid.deprecated.entity.other.attribute-name.html" + } + }, + "comment": "HTML attributes, deprecated", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "begin": "([^\\x{0020}\"'<>/=\\x{0000}-\\x{001F}\\x{007F}-\\x{009F}\\x{FDD0}-\\x{FDEF}\\x{FFFE}\\x{FFFF}\\x{1FFFE}\\x{1FFFF}\\x{2FFFE}\\x{2FFFF}\\x{3FFFE}\\x{3FFFF}\\x{4FFFE}\\x{4FFFF}\\x{5FFFE}\\x{5FFFF}\\x{6FFFE}\\x{6FFFF}\\x{7FFFE}\\x{7FFFF}\\x{8FFFE}\\x{8FFFF}\\x{9FFFE}\\x{9FFFF}\\x{AFFFE}\\x{AFFFF}\\x{BFFFE}\\x{BFFFF}\\x{CFFFE}\\x{CFFFF}\\x{DFFFE}\\x{DFFFF}\\x{EFFFE}\\x{EFFFF}\\x{FFFFE}\\x{FFFFF}\\x{10FFFE}\\x{10FFFF}]+)", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "comment": "Anything else that is valid", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.unrecognized.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "match": "[^\\s>]+", + "name": "invalid.illegal.character-not-allowed-here.html" + } + ] + }, + "attribute-interior": { + "patterns": [ + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "punctuation.separator.key-value.html" + } + }, + "end": "(?<=[^\\s=])(?!\\s*=)|(?=/?>)", + "patterns": [ + { + "match": "([^\\s\"'=<>`/]|/(?!>))+", + "name": "string.unquoted.html" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "name": "string.quoted.double.html", + "patterns": [ + { + "include": "#entities" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "name": "string.quoted.single.html", + "patterns": [ + { + "include": "#entities" + } + ] + }, + { + "match": "=", + "name": "invalid.illegal.unexpected-equals-sign.html" + } + ] + } + ] + }, + "cdata": { + "begin": "", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.cdata.html" + }, + "comment": { + "begin": "", + "name": "comment.block.html", + "patterns": [ + { + "match": "\\G-?>", + "name": "invalid.illegal.characters-not-allowed-here.html" + }, + { + "match": ")", + "name": "invalid.illegal.characters-not-allowed-here.html" + }, + { + "match": "--!>", + "name": "invalid.illegal.characters-not-allowed-here.html" + } + ] + }, + "core-minus-invalid": { + "comment": "This should be the root pattern array includes minus #tags-invalid", + "patterns": [ + { + "include": "#xml-processing" + }, + { + "include": "#comment" + }, + { + "include": "#doctype" + }, + { + "include": "#cdata" + }, + { + "include": "#tags-valid" + }, + { + "include": "#entities" + } + ] + }, + "doctype": { + "begin": "", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.doctype.html", + "patterns": [ + { + "match": "\\G(?i:DOCTYPE)", + "name": "entity.name.tag.html" + }, + { + "begin": "\"", + "end": "\"", + "name": "string.quoted.double.html" + }, + { + "match": "[^\\s>]+", + "name": "entity.other.attribute-name.html" + } + ] + }, + "entities": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.entity.html" + }, + "912": { + "name": "punctuation.definition.entity.html" + } + }, + "comment": "Yes this is a bit ridiculous, there are quite a lot of these", + "match": "(?x)\n\t\t\t\t\t\t(&)\t(?=[a-zA-Z])\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\t(a(s(ymp(eq)?|cr|t)|n(d(slope|d|v|and)?|g(s(t|ph)|zarr|e|le|rt(vb(d)?)?|msd(a(h|c|d|e|f|a|g|b))?)?)|c(y|irc|d|ute|E)?|tilde|o(pf|gon)|uml|p(id|os|prox(eq)?|e|E|acir)?|elig|f(r)?|w(conint|int)|l(pha|e(ph|fsym))|acute|ring|grave|m(p|a(cr|lg))|breve)|A(s(sign|cr)|nd|MP|c(y|irc)|tilde|o(pf|gon)|uml|pplyFunction|fr|Elig|lpha|acute|ring|grave|macr|breve))\n\t\t\t\t\t\t | (B(scr|cy|opf|umpeq|e(cause|ta|rnoullis)|fr|a(ckslash|r(v|wed))|reve)|b(s(cr|im(e)?|ol(hsub|b)?|emi)|n(ot|e(quiv)?)|c(y|ong)|ig(s(tar|qcup)|c(irc|up|ap)|triangle(down|up)|o(times|dot|plus)|uplus|vee|wedge)|o(t(tom)?|pf|wtie|x(h(d|u|D|U)?|times|H(d|u|D|U)?|d(R|l|r|L)|u(R|l|r|L)|plus|D(R|l|r|L)|v(R|h|H|l|r|L)?|U(R|l|r|L)|V(R|h|H|l|r|L)?|minus|box))|Not|dquo|u(ll(et)?|mp(e(q)?|E)?)|prime|e(caus(e)?|t(h|ween|a)|psi|rnou|mptyv)|karow|fr|l(ock|k(1(2|4)|34)|a(nk|ck(square|triangle(down|left|right)?|lozenge)))|a(ck(sim(eq)?|cong|prime|epsilon)|r(vee|wed(ge)?))|r(eve|vbar)|brk(tbrk)?))\n\t\t\t\t\t\t | (c(s(cr|u(p(e)?|b(e)?))|h(cy|i|eck(mark)?)|ylcty|c(irc|ups(sm)?|edil|a(ps|ron))|tdot|ir(scir|c(eq|le(d(R|circ|S|dash|ast)|arrow(left|right)))?|e|fnint|E|mid)?|o(n(int|g(dot)?)|p(y(sr)?|f|rod)|lon(e(q)?)?|m(p(fn|le(xes|ment))?|ma(t)?))|dot|u(darr(l|r)|p(s|c(up|ap)|or|dot|brcap)?|e(sc|pr)|vee|wed|larr(p)?|r(vearrow(left|right)|ly(eq(succ|prec)|vee|wedge)|arr(m)?|ren))|e(nt(erdot)?|dil|mptyv)|fr|w(conint|int)|lubs(uit)?|a(cute|p(s|c(up|ap)|dot|and|brcup)?|r(on|et))|r(oss|arr))|C(scr|hi|c(irc|onint|edil|aron)|ircle(Minus|Times|Dot|Plus)|Hcy|o(n(tourIntegral|int|gruent)|unterClockwiseContourIntegral|p(f|roduct)|lon(e)?)|dot|up(Cap)?|OPY|e(nterDot|dilla)|fr|lo(seCurly(DoubleQuote|Quote)|ckwiseContourIntegral)|a(yleys|cute|p(italDifferentialD)?)|ross))\n\t\t\t\t\t\t | (d(s(c(y|r)|trok|ol)|har(l|r)|c(y|aron)|t(dot|ri(f)?)|i(sin|e|v(ide(ontimes)?|onx)?|am(s|ond(suit)?)?|gamma)|Har|z(cy|igrarr)|o(t(square|plus|eq(dot)?|minus)?|ublebarwedge|pf|wn(harpoon(left|right)|downarrows|arrow)|llar)|d(otseq|a(rr|gger))?|u(har|arr)|jcy|e(lta|g|mptyv)|f(isht|r)|wangle|lc(orn|rop)|a(sh(v)?|leth|rr|gger)|r(c(orn|rop)|bkarow)|b(karow|lac)|Arr)|D(s(cr|trok)|c(y|aron)|Scy|i(fferentialD|a(critical(Grave|Tilde|Do(t|ubleAcute)|Acute)|mond))|o(t(Dot|Equal)?|uble(Right(Tee|Arrow)|ContourIntegral|Do(t|wnArrow)|Up(DownArrow|Arrow)|VerticalBar|L(ong(RightArrow|Left(RightArrow|Arrow))|eft(RightArrow|Tee|Arrow)))|pf|wn(Right(TeeVector|Vector(Bar)?)|Breve|Tee(Arrow)?|arrow|Left(RightVector|TeeVector|Vector(Bar)?)|Arrow(Bar|UpArrow)?))|Zcy|el(ta)?|D(otrahd)?|Jcy|fr|a(shv|rr|gger)))\n\t\t\t\t\t\t | (e(s(cr|im|dot)|n(sp|g)|c(y|ir(c)?|olon|aron)|t(h|a)|o(pf|gon)|dot|u(ro|ml)|p(si(v|lon)?|lus|ar(sl)?)|e|D(ot|Dot)|q(s(im|lant(less|gtr))|c(irc|olon)|u(iv(DD)?|est|als)|vparsl)|f(Dot|r)|l(s(dot)?|inters|l)?|a(ster|cute)|r(Dot|arr)|g(s(dot)?|rave)?|x(cl|ist|p(onentiale|ectation))|m(sp(1(3|4))?|pty(set|v)?|acr))|E(s(cr|im)|c(y|irc|aron)|ta|o(pf|gon)|NG|dot|uml|TH|psilon|qu(ilibrium|al(Tilde)?)|fr|lement|acute|grave|x(ists|ponentialE)|m(pty(SmallSquare|VerySmallSquare)|acr)))\n\t\t\t\t\t\t | (f(scr|nof|cy|ilig|o(pf|r(k(v)?|all))|jlig|partint|emale|f(ilig|l(ig|lig)|r)|l(tns|lig|at)|allingdotseq|r(own|a(sl|c(1(2|8|3|4|5|6)|78|2(3|5)|3(8|4|5)|45|5(8|6)))))|F(scr|cy|illed(SmallSquare|VerySmallSquare)|o(uriertrf|pf|rAll)|fr))\n\t\t\t\t\t\t | (G(scr|c(y|irc|edil)|t|opf|dot|T|Jcy|fr|amma(d)?|reater(Greater|SlantEqual|Tilde|Equal(Less)?|FullEqual|Less)|g|breve)|g(s(cr|im(e|l)?)|n(sim|e(q(q)?)?|E|ap(prox)?)|c(y|irc)|t(c(c|ir)|dot|quest|lPar|r(sim|dot|eq(qless|less)|less|a(pprox|rr)))?|imel|opf|dot|jcy|e(s(cc|dot(o(l)?)?|l(es)?)?|q(slant|q)?|l)?|v(nE|ertneqq)|fr|E(l)?|l(j|E|a)?|a(cute|p|mma(d)?)|rave|g(g)?|breve))\n\t\t\t\t\t\t | (h(s(cr|trok|lash)|y(phen|bull)|circ|o(ok(leftarrow|rightarrow)|pf|arr|rbar|mtht)|e(llip|arts(uit)?|rcon)|ks(earow|warow)|fr|a(irsp|lf|r(dcy|r(cir|w)?)|milt)|bar|Arr)|H(s(cr|trok)|circ|ilbertSpace|o(pf|rizontalLine)|ump(DownHump|Equal)|fr|a(cek|t)|ARDcy))\n\t\t\t\t\t\t | (i(s(cr|in(s(v)?|dot|v|E)?)|n(care|t(cal|prod|e(rcal|gers)|larhk)?|odot|fin(tie)?)?|c(y|irc)?|t(ilde)?|i(nfin|i(nt|int)|ota)?|o(cy|ta|pf|gon)|u(kcy|ml)|jlig|prod|e(cy|xcl)|quest|f(f|r)|acute|grave|m(of|ped|a(cr|th|g(part|e|line))))|I(scr|n(t(e(rsection|gral))?|visible(Comma|Times))|c(y|irc)|tilde|o(ta|pf|gon)|dot|u(kcy|ml)|Ocy|Jlig|fr|Ecy|acute|grave|m(plies|a(cr|ginaryI))?))\n\t\t\t\t\t\t | (j(s(cr|ercy)|c(y|irc)|opf|ukcy|fr|math)|J(s(cr|ercy)|c(y|irc)|opf|ukcy|fr))\n\t\t\t\t\t\t | (k(scr|hcy|c(y|edil)|opf|jcy|fr|appa(v)?|green)|K(scr|c(y|edil)|Hcy|opf|Jcy|fr|appa))\n\t\t\t\t\t\t | (l(s(h|cr|trok|im(e|g)?|q(uo(r)?|b)|aquo)|h(ar(d|u(l)?)|blk)|n(sim|e(q(q)?)?|E|ap(prox)?)|c(y|ub|e(il|dil)|aron)|Barr|t(hree|c(c|ir)|imes|dot|quest|larr|r(i(e|f)?|Par))?|Har|o(ng(left(arrow|rightarrow)|rightarrow|mapsto)|times|z(enge|f)?|oparrow(left|right)|p(f|lus|ar)|w(ast|bar)|a(ng|rr)|brk)|d(sh|ca|quo(r)?|r(dhar|ushar))|ur(dshar|uhar)|jcy|par(lt)?|e(s(s(sim|dot|eq(qgtr|gtr)|approx|gtr)|cc|dot(o(r)?)?|g(es)?)?|q(slant|q)?|ft(harpoon(down|up)|threetimes|leftarrows|arrow(tail)?|right(squigarrow|harpoons|arrow(s)?))|g)?|v(nE|ertneqq)|f(isht|loor|r)|E(g)?|l(hard|corner|tri|arr)?|a(ng(d|le)?|cute|t(e(s)?|ail)?|p|emptyv|quo|rr(sim|hk|tl|pl|fs|lp|b(fs)?)?|gran|mbda)|r(har(d)?|corner|tri|arr|m)|g(E)?|m(idot|oust(ache)?)|b(arr|r(k(sl(d|u)|e)|ac(e|k))|brk)|A(tail|arr|rr))|L(s(h|cr|trok)|c(y|edil|aron)|t|o(ng(RightArrow|left(arrow|rightarrow)|rightarrow|Left(RightArrow|Arrow))|pf|wer(RightArrow|LeftArrow))|T|e(ss(Greater|SlantEqual|Tilde|EqualGreater|FullEqual|Less)|ft(Right(Vector|Arrow)|Ceiling|T(ee(Vector|Arrow)?|riangle(Bar|Equal)?)|Do(ubleBracket|wn(TeeVector|Vector(Bar)?))|Up(TeeVector|DownVector|Vector(Bar)?)|Vector(Bar)?|arrow|rightarrow|Floor|A(ngleBracket|rrow(RightArrow|Bar)?)))|Jcy|fr|l(eftarrow)?|a(ng|cute|placetrf|rr|mbda)|midot))\n\t\t\t\t\t\t | (M(scr|cy|inusPlus|opf|u|e(diumSpace|llintrf)|fr|ap)|m(s(cr|tpos)|ho|nplus|c(y|omma)|i(nus(d(u)?|b)?|cro|d(cir|dot|ast)?)|o(dels|pf)|dash|u(ltimap|map)?|p|easuredangle|DDot|fr|l(cp|dr)|a(cr|p(sto(down|up|left)?)?|l(t(ese)?|e)|rker)))\n\t\t\t\t\t\t | (n(s(hort(parallel|mid)|c(cue|e|r)?|im(e(q)?)?|u(cc(eq)?|p(set(eq(q)?)?|e|E)?|b(set(eq(q)?)?|e|E)?)|par|qsu(pe|be)|mid)|Rightarrow|h(par|arr|Arr)|G(t(v)?|g)|c(y|ong(dot)?|up|edil|a(p|ron))|t(ilde|lg|riangle(left(eq)?|right(eq)?)|gl)|i(s(d)?|v)?|o(t(ni(v(c|a|b))?|in(dot|v(c|a|b)|E)?)?|pf)|dash|u(m(sp|ero)?)?|jcy|p(olint|ar(sl|t|allel)?|r(cue|e(c(eq)?)?)?)|e(s(im|ear)|dot|quiv|ar(hk|r(ow)?)|xist(s)?|Arr)?|v(sim|infin|Harr|dash|Dash|l(t(rie)?|e|Arr)|ap|r(trie|Arr)|g(t|e))|fr|w(near|ar(hk|r(ow)?)|Arr)|V(dash|Dash)|l(sim|t(ri(e)?)?|dr|e(s(s)?|q(slant|q)?|ft(arrow|rightarrow))?|E|arr|Arr)|a(ng|cute|tur(al(s)?)?|p(id|os|prox|E)?|bla)|r(tri(e)?|ightarrow|arr(c|w)?|Arr)|g(sim|t(r)?|e(s|q(slant|q)?)?|E)|mid|L(t(v)?|eft(arrow|rightarrow)|l)|b(sp|ump(e)?))|N(scr|c(y|edil|aron)|tilde|o(nBreakingSpace|Break|t(R(ightTriangle(Bar|Equal)?|everseElement)|Greater(Greater|SlantEqual|Tilde|Equal|FullEqual|Less)?|S(u(cceeds(SlantEqual|Tilde|Equal)?|perset(Equal)?|bset(Equal)?)|quareSu(perset(Equal)?|bset(Equal)?))|Hump(DownHump|Equal)|Nested(GreaterGreater|LessLess)|C(ongruent|upCap)|Tilde(Tilde|Equal|FullEqual)?|DoubleVerticalBar|Precedes(SlantEqual|Equal)?|E(qual(Tilde)?|lement|xists)|VerticalBar|Le(ss(Greater|SlantEqual|Tilde|Equal|Less)?|ftTriangle(Bar|Equal)?))?|pf)|u|e(sted(GreaterGreater|LessLess)|wLine|gative(MediumSpace|Thi(nSpace|ckSpace)|VeryThinSpace))|Jcy|fr|acute))\n\t\t\t\t\t\t | (o(s(cr|ol|lash)|h(m|bar)|c(y|ir(c)?)|ti(lde|mes(as)?)|S|int|opf|d(sold|iv|ot|ash|blac)|uml|p(erp|lus|ar)|elig|vbar|f(cir|r)|l(c(ir|ross)|t|ine|arr)|a(st|cute)|r(slope|igof|or|d(er(of)?|f|m)?|v|arr)?|g(t|on|rave)|m(i(nus|cron|d)|ega|acr))|O(s(cr|lash)|c(y|irc)|ti(lde|mes)|opf|dblac|uml|penCurly(DoubleQuote|Quote)|ver(B(ar|rac(e|ket))|Parenthesis)|fr|Elig|acute|r|grave|m(icron|ega|acr)))\n\t\t\t\t\t\t | (p(s(cr|i)|h(i(v)?|one|mmat)|cy|i(tchfork|v)?|o(intint|und|pf)|uncsp|er(cnt|tenk|iod|p|mil)|fr|l(us(sim|cir|two|d(o|u)|e|acir|mn|b)?|an(ck(h)?|kv))|ar(s(im|l)|t|a(llel)?)?|r(sim|n(sim|E|ap)|cue|ime(s)?|o(d|p(to)?|f(surf|line|alar))|urel|e(c(sim|n(sim|eqq|approx)|curlyeq|eq|approx)?)?|E|ap)?|m)|P(s(cr|i)|hi|cy|i|o(incareplane|pf)|fr|lusMinus|artialD|r(ime|o(duct|portion(al)?)|ecedes(SlantEqual|Tilde|Equal)?)?))\n\t\t\t\t\t\t | (q(scr|int|opf|u(ot|est(eq)?|at(int|ernions))|prime|fr)|Q(scr|opf|UOT|fr))\n\t\t\t\t\t\t | (R(s(h|cr)|ho|c(y|edil|aron)|Barr|ight(Ceiling|T(ee(Vector|Arrow)?|riangle(Bar|Equal)?)|Do(ubleBracket|wn(TeeVector|Vector(Bar)?))|Up(TeeVector|DownVector|Vector(Bar)?)|Vector(Bar)?|arrow|Floor|A(ngleBracket|rrow(Bar|LeftArrow)?))|o(undImplies|pf)|uleDelayed|e(verse(UpEquilibrium|E(quilibrium|lement)))?|fr|EG|a(ng|cute|rr(tl)?)|rightarrow)|r(s(h|cr|q(uo(r)?|b)|aquo)|h(o(v)?|ar(d|u(l)?))|nmid|c(y|ub|e(il|dil)|aron)|Barr|t(hree|imes|ri(e|f|ltri)?)|i(singdotseq|ng|ght(squigarrow|harpoon(down|up)|threetimes|left(harpoons|arrows)|arrow(tail)?|rightarrows))|Har|o(times|p(f|lus|ar)|a(ng|rr)|brk)|d(sh|ca|quo(r)?|ldhar)|uluhar|p(polint|ar(gt)?)|e(ct|al(s|ine|part)?|g)|f(isht|loor|r)|l(har|arr|m)|a(ng(d|e|le)?|c(ute|e)|t(io(nals)?|ail)|dic|emptyv|quo|rr(sim|hk|c|tl|pl|fs|w|lp|ap|b(fs)?)?)|rarr|x|moust(ache)?|b(arr|r(k(sl(d|u)|e)|ac(e|k))|brk)|A(tail|arr|rr)))\n\t\t\t\t\t\t | (s(s(cr|tarf|etmn|mile)|h(y|c(hcy|y)|ort(parallel|mid)|arp)|c(sim|y|n(sim|E|ap)|cue|irc|polint|e(dil)?|E|a(p|ron))?|t(ar(f)?|r(ns|aight(phi|epsilon)))|i(gma(v|f)?|m(ne|dot|plus|e(q)?|l(E)?|rarr|g(E)?)?)|zlig|o(pf|ftcy|l(b(ar)?)?)|dot(e|b)?|u(ng|cc(sim|n(sim|eqq|approx)|curlyeq|eq|approx)?|p(s(im|u(p|b)|et(neq(q)?|eq(q)?)?)|hs(ol|ub)|1|n(e|E)|2|d(sub|ot)|3|plus|e(dot)?|E|larr|mult)?|m|b(s(im|u(p|b)|et(neq(q)?|eq(q)?)?)|n(e|E)|dot|plus|e(dot)?|E|rarr|mult)?)|pa(des(uit)?|r)|e(swar|ct|tm(n|inus)|ar(hk|r(ow)?)|xt|mi|Arr)|q(su(p(set(eq)?|e)?|b(set(eq)?|e)?)|c(up(s)?|ap(s)?)|u(f|ar(e|f))?)|fr(own)?|w(nwar|ar(hk|r(ow)?)|Arr)|larr|acute|rarr|m(t(e(s)?)?|i(d|le)|eparsl|a(shp|llsetminus))|bquo)|S(scr|hort(RightArrow|DownArrow|UpArrow|LeftArrow)|c(y|irc|edil|aron)?|tar|igma|H(cy|CHcy)|opf|u(c(hThat|ceeds(SlantEqual|Tilde|Equal)?)|p(set|erset(Equal)?)?|m|b(set(Equal)?)?)|OFTcy|q(uare(Su(perset(Equal)?|bset(Equal)?)|Intersection|Union)?|rt)|fr|acute|mallCircle))\n\t\t\t\t\t\t | (t(s(hcy|c(y|r)|trok)|h(i(nsp|ck(sim|approx))|orn|e(ta(sym|v)?|re(4|fore))|k(sim|ap))|c(y|edil|aron)|i(nt|lde|mes(d|b(ar)?)?)|o(sa|p(cir|f(ork)?|bot)?|ea)|dot|prime|elrec|fr|w(ixt|ohead(leftarrow|rightarrow))|a(u|rget)|r(i(sb|time|dot|plus|e|angle(down|q|left(eq)?|right(eq)?)?|minus)|pezium|ade)|brk)|T(s(cr|trok)|RADE|h(i(nSpace|ckSpace)|e(ta|refore))|c(y|edil|aron)|S(cy|Hcy)|ilde(Tilde|Equal|FullEqual)?|HORN|opf|fr|a(u|b)|ripleDot))\n\t\t\t\t\t\t | (u(scr|h(ar(l|r)|blk)|c(y|irc)|t(ilde|dot|ri(f)?)|Har|o(pf|gon)|d(har|arr|blac)|u(arr|ml)|p(si(h|lon)?|harpoon(left|right)|downarrow|uparrows|lus|arrow)|f(isht|r)|wangle|l(c(orn(er)?|rop)|tri)|a(cute|rr)|r(c(orn(er)?|rop)|tri|ing)|grave|m(l|acr)|br(cy|eve)|Arr)|U(scr|n(ion(Plus)?|der(B(ar|rac(e|ket))|Parenthesis))|c(y|irc)|tilde|o(pf|gon)|dblac|uml|p(si(lon)?|downarrow|Tee(Arrow)?|per(RightArrow|LeftArrow)|DownArrow|Equilibrium|arrow|Arrow(Bar|DownArrow)?)|fr|a(cute|rr(ocir)?)|ring|grave|macr|br(cy|eve)))\n\t\t\t\t\t\t | (v(s(cr|u(pn(e|E)|bn(e|E)))|nsu(p|b)|cy|Bar(v)?|zigzag|opf|dash|prop|e(e(eq|bar)?|llip|r(t|bar))|Dash|fr|ltri|a(ngrt|r(s(igma|u(psetneq(q)?|bsetneq(q)?))|nothing|t(heta|riangle(left|right))|p(hi|i|ropto)|epsilon|kappa|r(ho)?))|rtri|Arr)|V(scr|cy|opf|dash(l)?|e(e|r(yThinSpace|t(ical(Bar|Separator|Tilde|Line))?|bar))|Dash|vdash|fr|bar))\n\t\t\t\t\t\t | (w(scr|circ|opf|p|e(ierp|d(ge(q)?|bar))|fr|r(eath)?)|W(scr|circ|opf|edge|fr))\n\t\t\t\t\t\t | (X(scr|i|opf|fr)|x(s(cr|qcup)|h(arr|Arr)|nis|c(irc|up|ap)|i|o(time|dot|p(f|lus))|dtri|u(tri|plus)|vee|fr|wedge|l(arr|Arr)|r(arr|Arr)|map))\n\t\t\t\t\t\t | (y(scr|c(y|irc)|icy|opf|u(cy|ml)|en|fr|ac(y|ute))|Y(scr|c(y|irc)|opf|uml|Icy|Ucy|fr|acute|Acy))\n\t\t\t\t\t\t | (z(scr|hcy|c(y|aron)|igrarr|opf|dot|e(ta|etrf)|fr|w(nj|j)|acute)|Z(scr|c(y|aron)|Hcy|opf|dot|e(ta|roWidthSpace)|fr|acute))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t(;)\n\t\t\t\t\t", + "name": "constant.character.entity.named.$2.html" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.entity.html" + }, + "3": { + "name": "punctuation.definition.entity.html" + } + }, + "match": "(&)#[0-9]+(;)", + "name": "constant.character.entity.numeric.decimal.html" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.entity.html" + }, + "3": { + "name": "punctuation.definition.entity.html" + } + }, + "match": "(&)#[xX][0-9a-fA-F]+(;)", + "name": "constant.character.entity.numeric.hexadecimal.html" + }, + { + "match": "&(?=[a-zA-Z0-9]+;)", + "name": "invalid.illegal.ambiguous-ampersand.html" + } + ] + }, + "math": { + "patterns": [ + { + "begin": "(?i)(<)(math)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.structure.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()", + "endCaptures": { + "0": { + "name": "meta.tag.structure.$2.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.element.structure.$2.html", + "patterns": [ + { + "begin": "(?)\\G", + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + } + ], + "repository": { + "attribute": { + "patterns": [ + { + "begin": "(s(hift|ymmetric|cript(sizemultiplier|level|minsize)|t(ackalign|retchy)|ide|u(pscriptshift|bscriptshift)|e(parator(s)?|lection)|rc)|h(eight|ref)|n(otation|umalign)|c(haralign|olumn(spa(n|cing)|width|lines|align)|lose|rossout)|i(n(dent(shift(first|last)?|target|align(first|last)?)|fixlinebreakstyle)|d)|o(pen|verflow)|d(i(splay(style)?|r)|e(nomalign|cimalpoint|pth))|position|e(dge|qual(columns|rows))|voffset|f(orm|ence|rame(spacing)?)|width|l(space|ine(thickness|leading|break(style|multchar)?)|o(ngdivstyle|cation)|ength|quote|argeop)|a(c(cent(under)?|tiontype)|l(t(text|img(-(height|valign|width))?)|ign(mentscope)?))|r(space|ow(spa(n|cing)|lines|align)|quote)|groupalign|x(link:href|mlns)|m(in(size|labelspacing)|ovablelimits|a(th(size|color|variant|background)|xsize))|bevelled)(?![\\w:-])", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "begin": "([^\\x{0020}\"'<>/=\\x{0000}-\\x{001F}\\x{007F}-\\x{009F}\\x{FDD0}-\\x{FDEF}\\x{FFFE}\\x{FFFF}\\x{1FFFE}\\x{1FFFF}\\x{2FFFE}\\x{2FFFF}\\x{3FFFE}\\x{3FFFF}\\x{4FFFE}\\x{4FFFF}\\x{5FFFE}\\x{5FFFF}\\x{6FFFE}\\x{6FFFF}\\x{7FFFE}\\x{7FFFF}\\x{8FFFE}\\x{8FFFF}\\x{9FFFE}\\x{9FFFF}\\x{AFFFE}\\x{AFFFF}\\x{BFFFE}\\x{BFFFF}\\x{CFFFE}\\x{CFFFF}\\x{DFFFE}\\x{DFFFF}\\x{EFFFE}\\x{EFFFF}\\x{FFFFE}\\x{FFFFF}\\x{10FFFE}\\x{10FFFF}]+)", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "comment": "Anything else that is valid", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.unrecognized.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "match": "[^\\s>]+", + "name": "invalid.illegal.character-not-allowed-here.html" + } + ] + }, + "tags": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#cdata" + }, + { + "captures": { + "0": { + "name": "meta.tag.structure.math.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(annotation|annotation-xml|semantics|menclose|merror|mfenced|mfrac|mpadded|mphantom|mroot|mrow|msqrt|mstyle|mmultiscripts|mover|mprescripts|msub|msubsup|msup|munder|munderover|none|mlabeledtr|mtable|mtd|mtr|mlongdiv|mscarries|mscarry|msgroup|msline|msrow|mstack|maction)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.structure.math.$2.html" + }, + { + "begin": "(?i)(<)(annotation|annotation-xml|semantics|menclose|merror|mfenced|mfrac|mpadded|mphantom|mroot|mrow|msqrt|mstyle|mmultiscripts|mover|mprescripts|msub|msubsup|msup|munder|munderover|none|mlabeledtr|mtable|mtd|mtr|mlongdiv|mscarries|mscarry|msgroup|msline|msrow|mstack|maction)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.structure.math.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.inline.math.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(mi|mn|mo|ms|mspace|mtext|maligngroup|malignmark)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.inline.math.$2.html" + }, + { + "begin": "(?i)(<)(mi|mn|mo|ms|mspace|mtext|maligngroup|malignmark)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.inline.math.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.object.math.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(mglyph)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.object.math.$2.html" + }, + { + "begin": "(?i)(<)(mglyph)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.object.math.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.other.invalid.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.unrecognized-tag.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(([\\w:]+))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.other.invalid.html" + }, + { + "begin": "(?i)(<)((\\w[^\\s>]*))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.other.invalid.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.unrecognized-tag.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.invalid.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "include": "#tags-invalid" + } + ] + } + } + }, + "svg": { + "patterns": [ + { + "begin": "(?i)(<)(svg)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.structure.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()", + "endCaptures": { + "0": { + "name": "meta.tag.structure.$2.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.element.structure.$2.html", + "patterns": [ + { + "begin": "(?)\\G", + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + } + ], + "repository": { + "attribute": { + "patterns": [ + { + "begin": "(s(hape-rendering|ystemLanguage|cale|t(yle|itchTiles|op-(color|opacity)|dDeviation|em(h|v)|artOffset|r(i(ng|kethrough-(thickness|position))|oke(-(opacity|dash(offset|array)|width|line(cap|join)|miterlimit))?))|urfaceScale|p(e(cular(Constant|Exponent)|ed)|acing|readMethod)|eed|lope)|h(oriz-(origin-x|adv-x)|eight|anging|ref(lang)?)|y(1|2|ChannelSelector)?|n(umOctaves|ame)|c(y|o(ntentS(criptType|tyleType)|lor(-(interpolation(-filters)?|profile|rendering))?)|ursor|l(ip(-(path|rule)|PathUnits)?|ass)|a(p-height|lcMode)|x)|t(ype|o|ext(-(decoration|anchor|rendering)|Length)|a(rget(X|Y)?|b(index|leValues))|ransform)|i(n(tercept|2)?|d(eographic)?|mage-rendering)|z(oomAndPan)?|o(p(erator|acity)|ver(flow|line-(thickness|position))|ffset|r(i(ent(ation)?|gin)|der))|d(y|i(splay|visor|ffuseConstant|rection)|ominant-baseline|ur|e(scent|celerate)|x)?|u(1|n(i(code(-(range|bidi))?|ts-per-em)|derline-(thickness|position))|2)|p(ing|oint(s(At(X|Y|Z))?|er-events)|a(nose-1|t(h(Length)?|tern(ContentUnits|Transform|Units))|int-order)|r(imitiveUnits|eserveA(spectRatio|lpha)))|e(n(d|able-background)|dgeMode|levation|x(ternalResourcesRequired|ponent))|v(i(sibility|ew(Box|Target))|-(hanging|ideographic|alphabetic|mathematical)|e(ctor-effect|r(sion|t-(origin-(y|x)|adv-y)))|alues)|k(1|2|3|e(y(Splines|Times|Points)|rn(ing|el(Matrix|UnitLength)))|4)?|f(y|il(ter(Res|Units)?|l(-(opacity|rule))?)|o(nt-(s(t(yle|retch)|ize(-adjust)?)|variant|family|weight)|rmat)|lood-(color|opacity)|r(om)?|x)|w(idth(s)?|ord-spacing|riting-mode)|l(i(ghting-color|mitingConeAngle)|ocal|e(ngthAdjust|tter-spacing)|ang)|a(scent|cc(umulate|ent-height)|ttribute(Name|Type)|zimuth|dditive|utoReverse|l(ignment-baseline|phabetic|lowReorder)|rabic-form|mplitude)|r(y|otate|e(s(tart|ult)|ndering-intent|peat(Count|Dur)|quired(Extensions|Features)|f(X|Y|errerPolicy)|l)|adius|x)?|g(1|2|lyph(Ref|-(name|orientation-(horizontal|vertical)))|radient(Transform|Units))|x(1|2|ChannelSelector|-height|link:(show|href|t(ype|itle)|a(ctuate|rcrole)|role)|ml:(space|lang|base))?|m(in|ode|e(thod|dia)|a(sk(ContentUnits|Units)?|thematical|rker(Height|-(start|end|mid)|Units|Width)|x))|b(y|ias|egin|ase(Profile|line-shift|Frequency)|box))(?![\\w:-])", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "begin": "([^\\x{0020}\"'<>/=\\x{0000}-\\x{001F}\\x{007F}-\\x{009F}\\x{FDD0}-\\x{FDEF}\\x{FFFE}\\x{FFFF}\\x{1FFFE}\\x{1FFFF}\\x{2FFFE}\\x{2FFFF}\\x{3FFFE}\\x{3FFFF}\\x{4FFFE}\\x{4FFFF}\\x{5FFFE}\\x{5FFFF}\\x{6FFFE}\\x{6FFFF}\\x{7FFFE}\\x{7FFFF}\\x{8FFFE}\\x{8FFFF}\\x{9FFFE}\\x{9FFFF}\\x{AFFFE}\\x{AFFFF}\\x{BFFFE}\\x{BFFFF}\\x{CFFFE}\\x{CFFFF}\\x{DFFFE}\\x{DFFFF}\\x{EFFFE}\\x{EFFFF}\\x{FFFFE}\\x{FFFFF}\\x{10FFFE}\\x{10FFFF}]+)", + "beginCaptures": { + "0": { + "name": "entity.other.attribute-name.html" + } + }, + "comment": "Anything else that is valid", + "end": "(?=\\s*+[^=\\s])", + "name": "meta.attribute.unrecognized.$1.html", + "patterns": [ + { + "include": "#attribute-interior" + } + ] + }, + { + "match": "[^\\s>]+", + "name": "invalid.illegal.character-not-allowed-here.html" + } + ] + }, + "tags": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#cdata" + }, + { + "captures": { + "0": { + "name": "meta.tag.metadata.svg.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(color-profile|desc|metadata|script|style|title)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.metadata.svg.$2.html" + }, + { + "begin": "(?i)(<)(color-profile|desc|metadata|script|style|title)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.metadata.svg.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.structure.svg.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(animateMotion|clipPath|defs|feComponentTransfer|feDiffuseLighting|feMerge|feSpecularLighting|filter|g|hatch|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|pattern|radialGradient|switch|text|textPath)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.structure.svg.$2.html" + }, + { + "begin": "(?i)(<)(animateMotion|clipPath|defs|feComponentTransfer|feDiffuseLighting|feMerge|feSpecularLighting|filter|g|hatch|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|pattern|radialGradient|switch|text|textPath)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.structure.svg.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.inline.svg.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(a|animate|discard|feBlend|feColorMatrix|feComposite|feConvolveMatrix|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feMergeNode|feMorphology|feOffset|fePointLight|feSpotLight|feTile|feTurbulence|hatchPath|mpath|set|solidcolor|stop|tspan)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.inline.svg.$2.html" + }, + { + "begin": "(?i)(<)(a|animate|discard|feBlend|feColorMatrix|feComposite|feConvolveMatrix|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feMergeNode|feMorphology|feOffset|fePointLight|feSpotLight|feTile|feTurbulence|hatchPath|mpath|set|solidcolor|stop|tspan)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.inline.svg.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.object.svg.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(circle|ellipse|feImage|foreignObject|image|line|path|polygon|polyline|rect|symbol|use|view)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.object.svg.$2.html" + }, + { + "begin": "(?i)(<)(a|circle|ellipse|feImage|foreignObject|image|line|path|polygon|polyline|rect|symbol|use|view)(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.object.svg.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.other.svg.$2.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)((altGlyph|altGlyphDef|altGlyphItem|animateColor|animateTransform|cursor|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|glyph|glyphRef|hkern|missing-glyph|tref|vkern))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.other.svg.$2.html" + }, + { + "begin": "(?i)(<)((altGlyph|altGlyphDef|altGlyphItem|animateColor|animateTransform|cursor|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|glyph|glyphRef|hkern|missing-glyph|tref|vkern))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.other.svg.$2.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "captures": { + "0": { + "name": "meta.tag.other.invalid.void.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.unrecognized-tag.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "match": "(?i)(<)(([\\w:]+))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(/>))", + "name": "meta.element.other.invalid.html" + }, + { + "begin": "(?i)(<)((\\w[^\\s>]*))(?=\\s|/?>)(?:(([^\"'>]|\"[^\"]*\"|'[^']*')*)(>))?", + "beginCaptures": { + "0": { + "name": "meta.tag.other.invalid.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.unrecognized-tag.html" + }, + "4": { + "patterns": [ + { + "include": "#attribute" + } + ] + }, + "6": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?i)()|(/>)|(?=)\\G", + "end": "(?=/>)|>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.invalid.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#tags" + } + ] + }, + { + "include": "#tags-invalid" + } + ] + } + } + }, + "tags-invalid": { + "patterns": [ + { + "begin": "(]*))(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.$2.html", + "patterns": [ + { + "include": "#attribute" + } + ] + } + ] + }, + "tags-valid": { + "patterns": [ + { + "begin": "(^[ \\t]+)?(?=<(?i:style)\\b(?!-))", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.embedded.leading.html" + } + }, + "end": "(?!\\G)([ \\t]*$\\n?)?", + "endCaptures": { + "1": { + "name": "punctuation.whitespace.embedded.trailing.html" + } + }, + "patterns": [ + { + "begin": "(?i)(<)(style)(?=\\s|/?>)", + "beginCaptures": { + "0": { + "name": "meta.tag.metadata.style.start.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "(?i)((<)/)(style)\\s*(>)", + "endCaptures": { + "0": { + "name": "meta.tag.metadata.style.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "source.css-ignored-vscode" + }, + "3": { + "name": "entity.name.tag.html" + }, + "4": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.embedded.block.html", + "patterns": [ + { + "begin": "\\G", + "captures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(>)", + "name": "meta.tag.metadata.style.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?!\\G)", + "end": "(?=)", + "endCaptures": { + "0": { + "name": "meta.tag.metadata.script.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.embedded.block.html", + "patterns": [ + { + "begin": "\\G", + "end": "(?=/)", + "patterns": [ + { + "begin": "(>)", + "beginCaptures": { + "0": { + "name": "meta.tag.metadata.script.start.html" + }, + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "((<))(?=/(?i:script))", + "endCaptures": { + "0": { + "name": "meta.tag.metadata.script.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "source.js-ignored-vscode" + } + }, + "patterns": [ + { + "begin": "\\G", + "end": "(?=\t\t\t\t\t\t\t\t\t\t\t# Tag without type attribute\n\t\t\t\t\t\t\t\t\t\t\t\t | type(?=[\\s=])\n\t\t\t\t\t\t\t\t\t\t\t\t \t(?!\\s*=\\s*\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t''\t\t\t\t\t\t\t\t# Empty\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t | \"\"\t\t\t\t\t\t\t\t\t# Values\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t | ('|\"|)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttext/\t\t\t\t\t\t\t# Text mime-types\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tjavascript(1\\.[0-5])?\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | x-javascript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | jscript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | livescript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | (x-)?ecmascript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | babel\t\t\t\t\t\t# Javascript variant currently\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t\t\t\t\t\t\t\t# recognized as such\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | application/\t\t\t\t\t# Application mime-types\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(x-)?javascript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | (x-)?ecmascript\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t | module\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\\s\"'>]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t)", + "name": "meta.tag.metadata.script.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?ix:\n\t\t\t\t\t\t\t\t\t\t\t\t(?=\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype\\s*=\\s*\n\t\t\t\t\t\t\t\t\t\t\t\t\t('|\"|)\n\t\t\t\t\t\t\t\t\t\t\t\t\ttext/\n\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tx-handlebars\n\t\t\t\t\t\t\t\t\t\t\t\t\t | (x-(handlebars-)?|ng-)?template\n\t\t\t\t\t\t\t\t\t\t\t\t\t | html\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t[\\s\"'>]\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t)", + "end": "((<))(?=/(?i:script))", + "endCaptures": { + "0": { + "name": "meta.tag.metadata.script.end.html" + }, + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "text.html.basic" + } + }, + "patterns": [ + { + "begin": "\\G", + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.script.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?!\\G)", + "end": "(?=)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.script.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?!\\G)", + "end": "(?=)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(noscript|title)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(col|hr|input)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(address|article|aside|blockquote|body|button|caption|colgroup|datalist|dd|details|dialog|div|dl|dt|fieldset|figcaption|figure|footer|form|head|header|hgroup|html|h[1-6]|label|legend|li|main|map|menu|meter|nav|ol|optgroup|option|output|p|pre|progress|section|select|slot|summary|table|tbody|td|template|textarea|tfoot|th|thead|tr|ul)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(area|br|wbr)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(a|abbr|b|bdi|bdo|cite|code|data|del|dfn|em|i|ins|kbd|mark|q|rp|rt|ruby|s|samp|small|span|strong|sub|sup|time|u|var)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(embed|img|param|source|track)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)(audio|canvas|iframe|object|picture|video)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((basefont|isindex))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.metadata.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((center|frameset|noembed|noframes))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.structure.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((acronym|big|blink|font|strike|tt|xmp))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.inline.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((frame))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.void.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((applet))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.deprecated.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.object.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)(<)((dir|keygen|listing|menuitem|plaintext|spacer))(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.no-longer-supported.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.$2.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "(?i)()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "invalid.illegal.no-longer-supported.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.other.$2.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "include": "#math" + }, + { + "include": "#svg" + }, + { + "begin": "(<)([a-zA-Z][.0-9_a-zA-Z\\x{00B7}\\x{00C0}-\\x{00D6}\\x{00D8}-\\x{00F6}\\x{00F8}-\\x{037D}\\x{037F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{203F}-\\x{2040}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}]*-[\\-.0-9_a-zA-Z\\x{00B7}\\x{00C0}-\\x{00D6}\\x{00D8}-\\x{00F6}\\x{00F8}-\\x{037D}\\x{037F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{203F}-\\x{2040}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}]*)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.custom.start.html", + "patterns": [ + { + "include": "#attribute" + } + ] + }, + { + "begin": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "name": "meta.tag.custom.end.html", + "patterns": [ + { + "include": "#attribute" + } + ] + } + ] + }, + "xml-processing": { + "begin": "(<\\?)(xml)", + "captures": { + "1": { + "name": "punctuation.definition.tag.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "(\\?>)", + "name": "meta.tag.metadata.processing.xml.html", + "patterns": [ + { + "include": "#attribute" + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/javascript.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/javascript.tmLanguage.json new file mode 100644 index 0000000000..724afaa402 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/javascript.tmLanguage.json @@ -0,0 +1,5876 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/33d8371c344f0b54746586313a939f742f9bcd3a", + "name": "javascript", + "scopeName": "source.js", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "include": "#shebang" + } + ], + "repository": { + "shebang": { + "name": "comment.line.shebang.js", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.js" + } + } + }, + "statements": { + "patterns": [ + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#label" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + }, + { + "name": "storage.modifier.js", + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js entity.name.function.js" + }, + "2": { + "name": "keyword.operator.definiteassignment.js" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js variable.other.constant.js entity.name.function.js" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "keyword.operator.rest.js" + }, + "3": { + "name": "entity.name.function.js variable.language.this.js" + }, + "4": { + "name": "entity.name.function.js" + }, + "5": { + "name": "keyword.operator.optional.js" + } + } + }, + { + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "meta.definition.property.js entity.name.function.js" + }, + "2": { + "name": "keyword.operator.optional.js" + }, + "3": { + "name": "keyword.operator.definiteassignment.js" + } + } + }, + { + "name": "meta.definition.property.js variable.object.property.js", + "match": "\\#?[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js", + "match": "\\?" + }, + { + "name": "keyword.operator.definiteassignment.js", + "match": "\\!" + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "keyword.operator.assignment.js" + } + }, + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "storage.modifier.js" + }, + "3": { + "name": "storage.modifier.js" + }, + "4": { + "name": "storage.modifier.async.js" + }, + "5": { + "name": "keyword.operator.new.js" + }, + "6": { + "name": "keyword.generator.asterisk.js" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + }, + { + "name": "meta.method.declaration.js", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "storage.modifier.js" + }, + "3": { + "name": "storage.modifier.js" + }, + "4": { + "name": "storage.modifier.async.js" + }, + "5": { + "name": "storage.type.property.js" + }, + "6": { + "name": "keyword.generator.asterisk.js" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + } + ] + }, + "object-literal-method-declaration": { + "name": "meta.method.declaration.js", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "storage.type.property.js" + }, + "3": { + "name": "keyword.generator.asterisk.js" + } + }, + "end": "(?=\\}|;|,)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + }, + { + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "storage.type.property.js" + }, + "3": { + "name": "keyword.generator.asterisk.js" + } + }, + "end": "(?=\\(|\\<)", + "patterns": [ + { + "include": "#method-declaration-name" + } + ] + } + ] + }, + "method-declaration-name": { + "begin": "(?x)(?=((\\b(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "variable.parameter.js" + } + } + }, + { + "name": "meta.arrow.js", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])", + "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js", + "begin": "(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.block.js" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.js" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-literal": { + "name": "meta.objectliteral.js", + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.js" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.js" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-member": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#object-literal-method-declaration" + }, + { + "name": "meta.object.member.js meta.object-literal.key.js", + "begin": "(?=\\[)", + "end": "(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#array-literal" + } + ] + }, + { + "name": "meta.object.member.js meta.object-literal.key.js", + "begin": "(?=[\\'\\\"\\`])", + "end": "(?=:)|((?<=[\\'\\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as)\\s+))))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + } + ] + }, + { + "name": "meta.object.member.js meta.object-literal.key.js", + "begin": "(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + }, + "1": { + "name": "entity.name.function.js" + } + } + }, + { + "name": "meta.object.member.js", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + } + } + }, + { + "name": "meta.object.member.js", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)", + "captures": { + "1": { + "name": "variable.other.readwrite.js" + } + } + }, + { + "name": "meta.object.member.js", + "match": "(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "meta.brace.round.js" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?<=\\>)", + "patterns": [ + { + "include": "#type-parameters" + } + ] + }, + { + "begin": "(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "meta.brace.round.js" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + }, + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.js" + } + }, + "end": "\\s*(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.js" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "patterns": [ + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "name": "meta.function-call.js", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + }, + { + "include": "#paren-expression" + } + ] + }, + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "end": "(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "name": "meta.function-call.js", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + } + ] + } + ] + }, + "function-call-target": { + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.js", + "match": "(\\#?[_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + "function-call-optionals": { + "patterns": [ + { + "name": "meta.function-call.js punctuation.accessor.optional.js", + "match": "\\?\\." + }, + { + "name": "meta.function-call.js keyword.operator.definiteassignment.js", + "match": "\\!" + } + ] + }, + "support-function-call-identifiers": { + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js", + "match": "(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + "paren-expression-possibly-arrow-with-typeparameters": { + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + "expression-inside-possibly-arrow-parens": { + "patterns": [ + { + "include": "#expressionWithoutIdentifiers" + }, + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#decorator" + }, + { + "include": "#destructuring-parameter" + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "keyword.operator.rest.js" + }, + "3": { + "name": "entity.name.function.js variable.language.this.js" + }, + "4": { + "name": "entity.name.function.js" + }, + "5": { + "name": "keyword.operator.optional.js" + } + } + }, + { + "match": "(?x)(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js", + "match": "<=|>=|<>|<|>" + }, + { + "match": "(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.logical.js" + }, + "2": { + "name": "keyword.operator.assignment.compound.js" + }, + "3": { + "name": "keyword.operator.arithmetic.js" + } + } + }, + { + "name": "keyword.operator.logical.js", + "match": "\\!|&&|\\|\\||\\?\\?" + }, + { + "name": "keyword.operator.bitwise.js", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js", + "match": "--" + }, + { + "name": "keyword.operator.increment.js", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js", + "match": "%|\\*|/|-|\\+" + }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))", + "end": "(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))", + "endCaptures": { + "1": { + "name": "keyword.operator.assignment.compound.js" + }, + "2": { + "name": "keyword.operator.arithmetic.js" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, + { + "match": "(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.assignment.compound.js" + }, + "2": { + "name": "keyword.operator.arithmetic.js" + } + } + } + ] + }, + "typeof-operator": { + "begin": "(?:&|{\\?]|$|;|^\\s*$|(?:^\\s*(?:abstract|async|class|const|declare|enum|export|function|import|interface|let|module|namespace|return|type|var)\\b))", + "patterns": [ + { + "include": "#expression" + } + ] + }, + "literal": { + "patterns": [ + { + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.js", + "begin": "\\s*(\\[)", + "beginCaptures": { + "1": { + "name": "meta.brace.square.js" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.js" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.js", + "match": "\\b(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + }, + "3": { + "name": "support.variable.property.js" + }, + "4": { + "name": "support.constant.js" + } + } + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + }, + "3": { + "name": "entity.name.function.js" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + }, + "3": { + "name": "variable.other.constant.property.js" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + }, + "3": { + "name": "variable.other.property.js" + } + } + }, + { + "name": "variable.other.constant.js", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + }, + "3": { + "name": "variable.other.constant.object.property.js" + }, + "4": { + "name": "variable.other.object.property.js" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js" + }, + "2": { + "name": "variable.other.object.js" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "parameter-type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?=[,)])|(?==[^>])", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "possibly-arrow-return-type": { + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "beginCaptures": { + "1": { + "name": "meta.arrow.js meta.return.type.arrow.js keyword.operator.type.annotation.js" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "contentName": "meta.arrow.js meta.return.type.arrow.js", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "arrow-return-type-body": { + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js", + "match": "(?)" + } + ] + }, + "type-arguments": { + "name": "meta.type.parameters.js", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + "type-arguments-body": { + "patterns": [ + { + "match": "(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", + "captures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "keyword.operator.rest.js" + }, + "3": { + "name": "entity.name.function.js variable.language.this.js" + }, + "4": { + "name": "entity.name.function.js" + }, + "5": { + "name": "keyword.operator.optional.js" + } + } + }, + { + "match": "(?x)(?:(?)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + } + ] + }, + { + "name": "meta.type.constructor.js", + "begin": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?:\\?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js", + "match": "(?)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.js punctuation.definition.typeparameters.end.js" + } + }, + "contentName": "meta.type.parameters.js", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "begin": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)", + "beginCaptures": { + "1": { + "name": "entity.name.type.js" + }, + "2": { + "name": "meta.type.parameters.js punctuation.definition.typeparameters.begin.js" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.js punctuation.definition.typeparameters.end.js" + } + }, + "contentName": "meta.type.parameters.js", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "entity.name.type.module.js" + }, + "2": { + "name": "punctuation.accessor.js" + }, + "3": { + "name": "punctuation.accessor.optional.js" + } + } + }, + { + "name": "entity.name.type.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "punctuation-comma": { + "name": "punctuation.separator.comma.js", + "match": "," + }, + "punctuation-semicolon": { + "name": "punctuation.terminator.statement.js", + "match": ";" + }, + "punctuation-accessor": { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "punctuation.accessor.optional.js" + } + } + }, + "string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template" + } + ] + }, + "qstring-double": { + "name": "string.quoted.double.js", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "(\")|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js" + }, + "2": { + "name": "invalid.illegal.newline.js" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "qstring-single": { + "name": "string.quoted.single.js", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "(\\')|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js" + }, + "2": { + "name": "invalid.illegal.newline.js" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.js", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "template": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.js", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js" + }, + "2": { + "name": "punctuation.definition.string.template.begin.js" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.js" + } + }, + "patterns": [ + { + "include": "#template-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-call": { + "patterns": [ + { + "name": "string.template.js", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "end": "(?=`)", + "patterns": [ + { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.tagged-template.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#type-arguments" + } + ] + }, + { + "name": "string.template.js", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js" + } + }, + "end": "(?=`)", + "patterns": [ + { + "include": "#type-arguments" + } + ] + } + ] + }, + "template-substitution-element": { + "name": "meta.template.expression.js", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.js" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.js" + } + }, + "patterns": [ + { + "include": "#expression" + } + ], + "contentName": "meta.embedded.line.js" + }, + "type-string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template-type" + } + ] + }, + "template-type": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.js", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js" + }, + "2": { + "name": "punctuation.definition.string.template.begin.js" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.js" + } + }, + "patterns": [ + { + "include": "#template-type-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-type-substitution-element": { + "name": "meta.template.expression.js", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.js" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.js" + } + }, + "patterns": [ + { + "include": "#type" + } + ], + "contentName": "meta.embedded.line.js" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.js", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "(/)([dgimsuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js" + }, + "2": { + "name": "keyword.other.js" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" + }, + { + "name": "keyword.operator.or.regexp", + "match": "\\|" + }, + { + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + } + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." + }, + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] + }, + "comment": { + "patterns": [ + { + "name": "comment.block.documentation.js", + "begin": "/\\*\\*(?!/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "patterns": [ + { + "include": "#docblock" + } + ] + }, + { + "name": "comment.block.js", + "begin": "(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js" + }, + "2": { + "name": "storage.type.internaldeclaration.js" + }, + "3": { + "name": "punctuation.decorator.internaldeclaration.js" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + } + }, + { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.js" + }, + "2": { + "name": "comment.line.double-slash.js" + }, + "3": { + "name": "punctuation.definition.comment.js" + }, + "4": { + "name": "storage.type.internaldeclaration.js" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.js" + } + }, + "end": "(?=$)", + "contentName": "comment.line.double-slash.js" + } + ] + }, + "single-line-comment-consuming-line-ending": { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.js" + }, + "2": { + "name": "comment.line.double-slash.js" + }, + "3": { + "name": "punctuation.definition.comment.js" + }, + "4": { + "name": "storage.type.internaldeclaration.js" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.js" + } + }, + "end": "(?=^)", + "contentName": "comment.line.double-slash.js" + }, + "directives": { + "name": "comment.line.triple-slash.directive.js", + "begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "(?=$)", + "patterns": [ + { + "name": "meta.tag.js", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js" + }, + "2": { + "name": "entity.name.tag.directive.js" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js", + "match": "path|types|no-default-lib|lib|name" + }, + { + "name": "keyword.operator.assignment.js", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + }, + { + "match": "((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js", + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.namespace.js" + }, + "3": { + "name": "punctuation.separator.namespace.js" + }, + "4": { + "name": "entity.name.tag.js" + }, + "5": { + "name": "support.class.component.js" + }, + "6": { + "name": "punctuation.definition.tag.end.js" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.namespace.js" + }, + "3": { + "name": "punctuation.separator.namespace.js" + }, + "4": { + "name": "entity.name.tag.js" + }, + "5": { + "name": "support.class.component.js" + }, + "6": { + "name": "punctuation.definition.tag.end.js" + } + }, + "contentName": "meta.jsx.children.js", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js", + "begin": "(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js" + }, + "2": { + "name": "punctuation.definition.tag.begin.js" + }, + "3": { + "name": "entity.name.tag.namespace.js" + }, + "4": { + "name": "punctuation.separator.namespace.js" + }, + "5": { + "name": "entity.name.tag.js" + }, + "6": { + "name": "support.class.component.js" + }, + "7": { + "name": "punctuation.definition.tag.end.js" + } + }, + "patterns": [ + { + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.namespace.js" + }, + "3": { + "name": "punctuation.separator.namespace.js" + }, + "4": { + "name": "entity.name.tag.js" + }, + "5": { + "name": "support.class.component.js" + } + }, + "end": "(?=[/]?>)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-arguments" + }, + { + "include": "#jsx-tag-attributes" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n (?:([_$[:alpha:]][-_$[:alnum:].]*)(:))?\n ([_$[:alpha:]][-_$[:alnum:]]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.namespace.js" + }, + "2": { + "name": "punctuation.separator.namespace.js" + }, + "3": { + "name": "entity.other.attribute-name.js" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js", + "match": "\\S+" + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/json.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/json.tmLanguage.json new file mode 100644 index 0000000000..f11db55c67 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/json.tmLanguage.json @@ -0,0 +1,213 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/vscode-JSON.tmLanguage/blob/master/JSON.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/vscode-JSON.tmLanguage/commit/9bd83f1c252b375e957203f21793316203f61f70", + "name": "json", + "scopeName": "source.json", + "patterns": [ + { + "include": "#value" + } + ], + "repository": { + "array": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.array.begin.json" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.json" + } + }, + "name": "meta.structure.array.json", + "patterns": [ + { + "include": "#value" + }, + { + "match": ",", + "name": "punctuation.separator.array.json" + }, + { + "match": "[^\\s\\]]", + "name": "invalid.illegal.expected-array-separator.json" + } + ] + }, + "comments": { + "patterns": [ + { + "begin": "/\\*\\*(?!/)", + "captures": { + "0": { + "name": "punctuation.definition.comment.json" + } + }, + "end": "\\*/", + "name": "comment.block.documentation.json" + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.json" + } + }, + "end": "\\*/", + "name": "comment.block.json" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.comment.json" + } + }, + "match": "(//).*$\\n?", + "name": "comment.line.double-slash.js" + } + ] + }, + "constant": { + "match": "\\b(?:true|false|null)\\b", + "name": "constant.language.json" + }, + "number": { + "match": "(?x) # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional", + "name": "constant.numeric.json" + }, + "object": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.dictionary.begin.json" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.dictionary.end.json" + } + }, + "name": "meta.structure.dictionary.json", + "patterns": [ + { + "comment": "the JSON object key", + "include": "#objectkey" + }, + { + "include": "#comments" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.dictionary.key-value.json" + } + }, + "end": "(,)|(?=\\})", + "endCaptures": { + "1": { + "name": "punctuation.separator.dictionary.pair.json" + } + }, + "name": "meta.structure.dictionary.value.json", + "patterns": [ + { + "comment": "the JSON object value", + "include": "#value" + }, + { + "match": "[^\\s,]", + "name": "invalid.illegal.expected-dictionary-separator.json" + } + ] + }, + { + "match": "[^\\s\\}]", + "name": "invalid.illegal.expected-dictionary-separator.json" + } + ] + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.json" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.json" + } + }, + "name": "string.quoted.double.json", + "patterns": [ + { + "include": "#stringcontent" + } + ] + }, + "objectkey": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.support.type.property-name.begin.json" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.support.type.property-name.end.json" + } + }, + "name": "string.json support.type.property-name.json", + "patterns": [ + { + "include": "#stringcontent" + } + ] + }, + "stringcontent": { + "patterns": [ + { + "match": "(?x) # turn on extended mode\n \\\\ # a literal backslash\n (?: # ...followed by...\n [\"\\\\/bfnrt] # one of these characters\n | # ...or...\n u # a u\n [0-9a-fA-F]{4}) # and four hex digits", + "name": "constant.character.escape.json" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unrecognized-string-escape.json" + } + ] + }, + "value": { + "patterns": [ + { + "include": "#constant" + }, + { + "include": "#number" + }, + { + "include": "#string" + }, + { + "include": "#array" + }, + { + "include": "#object" + }, + { + "include": "#comments" + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/jsonc.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/jsonc.tmLanguage.json new file mode 100644 index 0000000000..a440d4d590 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/jsonc.tmLanguage.json @@ -0,0 +1,213 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/vscode-JSON.tmLanguage/blob/master/JSON.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/vscode-JSON.tmLanguage/commit/9bd83f1c252b375e957203f21793316203f61f70", + "name": "jsonc", + "scopeName": "source.json.comments", + "patterns": [ + { + "include": "#value" + } + ], + "repository": { + "array": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.array.begin.json.comments" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.json.comments" + } + }, + "name": "meta.structure.array.json.comments", + "patterns": [ + { + "include": "#value" + }, + { + "match": ",", + "name": "punctuation.separator.array.json.comments" + }, + { + "match": "[^\\s\\]]", + "name": "invalid.illegal.expected-array-separator.json.comments" + } + ] + }, + "comments": { + "patterns": [ + { + "begin": "/\\*\\*(?!/)", + "captures": { + "0": { + "name": "punctuation.definition.comment.json.comments" + } + }, + "end": "\\*/", + "name": "comment.block.documentation.json.comments" + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.json.comments" + } + }, + "end": "\\*/", + "name": "comment.block.json.comments" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.comment.json.comments" + } + }, + "match": "(//).*$\\n?", + "name": "comment.line.double-slash.js" + } + ] + }, + "constant": { + "match": "\\b(?:true|false|null)\\b", + "name": "constant.language.json.comments" + }, + "number": { + "match": "(?x) # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional", + "name": "constant.numeric.json.comments" + }, + "object": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.dictionary.begin.json.comments" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.dictionary.end.json.comments" + } + }, + "name": "meta.structure.dictionary.json.comments", + "patterns": [ + { + "comment": "the JSON object key", + "include": "#objectkey" + }, + { + "include": "#comments" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.dictionary.key-value.json.comments" + } + }, + "end": "(,)|(?=\\})", + "endCaptures": { + "1": { + "name": "punctuation.separator.dictionary.pair.json.comments" + } + }, + "name": "meta.structure.dictionary.value.json.comments", + "patterns": [ + { + "comment": "the JSON object value", + "include": "#value" + }, + { + "match": "[^\\s,]", + "name": "invalid.illegal.expected-dictionary-separator.json.comments" + } + ] + }, + { + "match": "[^\\s\\}]", + "name": "invalid.illegal.expected-dictionary-separator.json.comments" + } + ] + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.json.comments" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.json.comments" + } + }, + "name": "string.quoted.double.json.comments", + "patterns": [ + { + "include": "#stringcontent" + } + ] + }, + "objectkey": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.support.type.property-name.begin.json.comments" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.support.type.property-name.end.json.comments" + } + }, + "name": "string.json.comments support.type.property-name.json.comments", + "patterns": [ + { + "include": "#stringcontent" + } + ] + }, + "stringcontent": { + "patterns": [ + { + "match": "(?x) # turn on extended mode\n \\\\ # a literal backslash\n (?: # ...followed by...\n [\"\\\\/bfnrt] # one of these characters\n | # ...or...\n u # a u\n [0-9a-fA-F]{4}) # and four hex digits", + "name": "constant.character.escape.json.comments" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unrecognized-string-escape.json.comments" + } + ] + }, + "value": { + "patterns": [ + { + "include": "#constant" + }, + { + "include": "#number" + }, + { + "include": "#string" + }, + { + "include": "#array" + }, + { + "include": "#object" + }, + { + "include": "#comments" + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/jsx.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/jsx.tmLanguage.json new file mode 100644 index 0000000000..9456ccc21b --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/jsx.tmLanguage.json @@ -0,0 +1,5876 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/33d8371c344f0b54746586313a939f742f9bcd3a", + "name": "jsx", + "scopeName": "source.js.jsx", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "include": "#shebang" + } + ], + "repository": { + "shebang": { + "name": "comment.line.shebang.js.jsx", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + } + } + }, + "statements": { + "patterns": [ + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#label" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + }, + { + "name": "storage.modifier.js.jsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" + }, + "2": { + "name": "keyword.operator.definiteassignment.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx entity.name.function.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "meta.definition.property.js.jsx entity.name.function.js.jsx" + }, + "2": { + "name": "keyword.operator.optional.js.jsx" + }, + "3": { + "name": "keyword.operator.definiteassignment.js.jsx" + } + } + }, + { + "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", + "match": "\\#?[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js.jsx", + "match": "\\?" + }, + { + "name": "keyword.operator.definiteassignment.js.jsx", + "match": "\\!" + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "keyword.operator.assignment.js.jsx" + } + }, + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "storage.modifier.js.jsx" + }, + "3": { + "name": "storage.modifier.js.jsx" + }, + "4": { + "name": "storage.modifier.async.js.jsx" + }, + "5": { + "name": "keyword.operator.new.js.jsx" + }, + "6": { + "name": "keyword.generator.asterisk.js.jsx" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + }, + { + "name": "meta.method.declaration.js.jsx", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "storage.modifier.js.jsx" + }, + "3": { + "name": "storage.modifier.js.jsx" + }, + "4": { + "name": "storage.modifier.async.js.jsx" + }, + "5": { + "name": "storage.type.property.js.jsx" + }, + "6": { + "name": "keyword.generator.asterisk.js.jsx" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + } + ] + }, + "object-literal-method-declaration": { + "name": "meta.method.declaration.js.jsx", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "storage.type.property.js.jsx" + }, + "3": { + "name": "keyword.generator.asterisk.js.jsx" + } + }, + "end": "(?=\\}|;|,)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + }, + { + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "storage.type.property.js.jsx" + }, + "3": { + "name": "keyword.generator.asterisk.js.jsx" + } + }, + "end": "(?=\\(|\\<)", + "patterns": [ + { + "include": "#method-declaration-name" + } + ] + } + ] + }, + "method-declaration-name": { + "begin": "(?x)(?=((\\b(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "variable.parameter.js.jsx" + } + } + }, + { + "name": "meta.arrow.js.jsx", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])", + "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js.jsx", + "begin": "(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.block.js.jsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.js.jsx" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-literal": { + "name": "meta.objectliteral.js.jsx", + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.js.jsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.js.jsx" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-member": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#object-literal-method-declaration" + }, + { + "name": "meta.object.member.js.jsx meta.object-literal.key.js.jsx", + "begin": "(?=\\[)", + "end": "(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#array-literal" + } + ] + }, + { + "name": "meta.object.member.js.jsx meta.object-literal.key.js.jsx", + "begin": "(?=[\\'\\\"\\`])", + "end": "(?=:)|((?<=[\\'\\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as)\\s+))))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + } + ] + }, + { + "name": "meta.object.member.js.jsx meta.object-literal.key.js.jsx", + "begin": "(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + }, + "1": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)", + "captures": { + "1": { + "name": "variable.other.readwrite.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "match": "(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "meta.brace.round.js.jsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?<=\\>)", + "patterns": [ + { + "include": "#type-parameters" + } + ] + }, + { + "begin": "(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "meta.brace.round.js.jsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + }, + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "end": "\\s*(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "patterns": [ + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "name": "meta.function-call.js.jsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + }, + { + "include": "#paren-expression" + } + ] + }, + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "end": "(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "name": "meta.function-call.js.jsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + } + ] + } + ] + }, + "function-call-target": { + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.js.jsx", + "match": "(\\#?[_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + "function-call-optionals": { + "patterns": [ + { + "name": "meta.function-call.js.jsx punctuation.accessor.optional.js.jsx", + "match": "\\?\\." + }, + { + "name": "meta.function-call.js.jsx keyword.operator.definiteassignment.js.jsx", + "match": "\\!" + } + ] + }, + "support-function-call-identifiers": { + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js.jsx", + "match": "(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + "paren-expression-possibly-arrow-with-typeparameters": { + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + "expression-inside-possibly-arrow-parens": { + "patterns": [ + { + "include": "#expressionWithoutIdentifiers" + }, + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#decorator" + }, + { + "include": "#destructuring-parameter" + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": "(?x)(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js.jsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js.jsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js.jsx", + "match": "<=|>=|<>|<|>" + }, + { + "match": "(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.logical.js.jsx" + }, + "2": { + "name": "keyword.operator.assignment.compound.js.jsx" + }, + "3": { + "name": "keyword.operator.arithmetic.js.jsx" + } + } + }, + { + "name": "keyword.operator.logical.js.jsx", + "match": "\\!|&&|\\|\\||\\?\\?" + }, + { + "name": "keyword.operator.bitwise.js.jsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js.jsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.js.jsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js.jsx", + "match": "%|\\*|/|-|\\+" + }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))", + "end": "(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))", + "endCaptures": { + "1": { + "name": "keyword.operator.assignment.compound.js.jsx" + }, + "2": { + "name": "keyword.operator.arithmetic.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, + { + "match": "(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.assignment.compound.js.jsx" + }, + "2": { + "name": "keyword.operator.arithmetic.js.jsx" + } + } + } + ] + }, + "typeof-operator": { + "begin": "(?:&|{\\?]|$|;|^\\s*$|(?:^\\s*(?:abstract|async|class|const|declare|enum|export|function|import|interface|let|module|namespace|return|type|var)\\b))", + "patterns": [ + { + "include": "#expression" + } + ] + }, + "literal": { + "patterns": [ + { + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.js.jsx", + "begin": "\\s*(\\[)", + "beginCaptures": { + "1": { + "name": "meta.brace.square.js.jsx" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.js.jsx", + "match": "\\b(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + }, + "3": { + "name": "support.variable.property.js.jsx" + }, + "4": { + "name": "support.constant.js.jsx" + } + } + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + }, + "3": { + "name": "variable.other.constant.property.js.jsx" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + }, + "3": { + "name": "variable.other.property.js.jsx" + } + } + }, + { + "name": "variable.other.constant.js.jsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + }, + "3": { + "name": "variable.other.constant.object.property.js.jsx" + }, + "4": { + "name": "variable.other.object.property.js.jsx" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js.jsx" + }, + "2": { + "name": "variable.other.object.js.jsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "parameter-type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?=[,)])|(?==[^>])", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js.jsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "possibly-arrow-return-type": { + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "beginCaptures": { + "1": { + "name": "meta.arrow.js.jsx meta.return.type.arrow.js.jsx keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "contentName": "meta.arrow.js.jsx meta.return.type.arrow.js.jsx", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "arrow-return-type-body": { + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js.jsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js.jsx", + "match": "(?)" + } + ] + }, + "type-arguments": { + "name": "meta.type.parameters.js.jsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + "type-arguments-body": { + "patterns": [ + { + "match": "(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": "(?x)(?:(?)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + } + ] + }, + { + "name": "meta.type.constructor.js.jsx", + "begin": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js.jsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?:\\?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js.jsx", + "match": "(?)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.js.jsx punctuation.definition.typeparameters.end.js.jsx" + } + }, + "contentName": "meta.type.parameters.js.jsx", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "begin": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)", + "beginCaptures": { + "1": { + "name": "entity.name.type.js.jsx" + }, + "2": { + "name": "meta.type.parameters.js.jsx punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.js.jsx punctuation.definition.typeparameters.end.js.jsx" + } + }, + "contentName": "meta.type.parameters.js.jsx", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "entity.name.type.module.js.jsx" + }, + "2": { + "name": "punctuation.accessor.js.jsx" + }, + "3": { + "name": "punctuation.accessor.optional.js.jsx" + } + } + }, + { + "name": "entity.name.type.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "punctuation-comma": { + "name": "punctuation.separator.comma.js.jsx", + "match": "," + }, + "punctuation-semicolon": { + "name": "punctuation.terminator.statement.js.jsx", + "match": ";" + }, + "punctuation-accessor": { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "punctuation.accessor.optional.js.jsx" + } + } + }, + "string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template" + } + ] + }, + "qstring-double": { + "name": "string.quoted.double.js.jsx", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(\")|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "invalid.illegal.newline.js.jsx" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "qstring-single": { + "name": "string.quoted.single.js.jsx", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(\\')|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "invalid.illegal.newline.js.jsx" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.js.jsx", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "template": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js.jsx" + }, + "2": { + "name": "punctuation.definition.string.template.begin.js.jsx" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#template-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-call": { + "patterns": [ + { + "name": "string.template.js.jsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "end": "(?=`)", + "patterns": [ + { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.tagged-template.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#type-arguments" + } + ] + }, + { + "name": "string.template.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js.jsx" + } + }, + "end": "(?=`)", + "patterns": [ + { + "include": "#type-arguments" + } + ] + } + ] + }, + "template-substitution-element": { + "name": "meta.template.expression.js.jsx", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.js.jsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ], + "contentName": "meta.embedded.line.js.jsx" + }, + "type-string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template-type" + } + ] + }, + "template-type": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.js.jsx" + }, + "2": { + "name": "punctuation.definition.string.template.begin.js.jsx" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#template-type-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-type-substitution-element": { + "name": "meta.template.expression.js.jsx", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.js.jsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#type" + } + ], + "contentName": "meta.embedded.line.js.jsx" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.js.jsx", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(/)([dgimsuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "keyword.other.js.jsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js.jsx", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" + }, + { + "name": "keyword.operator.or.regexp", + "match": "\\|" + }, + { + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + } + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." + }, + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] + }, + "comment": { + "patterns": [ + { + "name": "comment.block.documentation.js.jsx", + "begin": "/\\*\\*(?!/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "patterns": [ + { + "include": "#docblock" + } + ] + }, + { + "name": "comment.block.js.jsx", + "begin": "(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + }, + "2": { + "name": "storage.type.internaldeclaration.js.jsx" + }, + "3": { + "name": "punctuation.decorator.internaldeclaration.js.jsx" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.js.jsx" + } + } + }, + { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.js.jsx" + }, + "2": { + "name": "comment.line.double-slash.js.jsx" + }, + "3": { + "name": "punctuation.definition.comment.js.jsx" + }, + "4": { + "name": "storage.type.internaldeclaration.js.jsx" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.js.jsx" + } + }, + "end": "(?=$)", + "contentName": "comment.line.double-slash.js.jsx" + } + ] + }, + "single-line-comment-consuming-line-ending": { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.js.jsx" + }, + "2": { + "name": "comment.line.double-slash.js.jsx" + }, + "3": { + "name": "punctuation.definition.comment.js.jsx" + }, + "4": { + "name": "storage.type.internaldeclaration.js.jsx" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.js.jsx" + } + }, + "end": "(?=^)", + "contentName": "comment.line.double-slash.js.jsx" + }, + "directives": { + "name": "comment.line.triple-slash.directive.js.jsx", + "begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "end": "(?=$)", + "patterns": [ + { + "name": "meta.tag.js.jsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js.jsx" + }, + "2": { + "name": "entity.name.tag.directive.js.jsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js.jsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js.jsx", + "match": "path|types|no-default-lib|lib|name" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js.jsx" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js.jsx" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + }, + { + "match": "((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js.jsx", + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.namespace.js.jsx" + }, + "3": { + "name": "punctuation.separator.namespace.js.jsx" + }, + "4": { + "name": "entity.name.tag.js.jsx" + }, + "5": { + "name": "support.class.component.js.jsx" + }, + "6": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.namespace.js.jsx" + }, + "3": { + "name": "punctuation.separator.namespace.js.jsx" + }, + "4": { + "name": "entity.name.tag.js.jsx" + }, + "5": { + "name": "support.class.component.js.jsx" + }, + "6": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "contentName": "meta.jsx.children.js.jsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js.jsx", + "begin": "(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.namespace.js.jsx" + }, + "4": { + "name": "punctuation.separator.namespace.js.jsx" + }, + "5": { + "name": "entity.name.tag.js.jsx" + }, + "6": { + "name": "support.class.component.js.jsx" + }, + "7": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.namespace.js.jsx" + }, + "3": { + "name": "punctuation.separator.namespace.js.jsx" + }, + "4": { + "name": "entity.name.tag.js.jsx" + }, + "5": { + "name": "support.class.component.js.jsx" + } + }, + "end": "(?=[/]?>)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-arguments" + }, + { + "include": "#jsx-tag-attributes" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n (?:([_$[:alpha:]][-_$[:alnum:].]*)(:))?\n ([_$[:alpha:]][-_$[:alnum:]]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.namespace.js.jsx" + }, + "2": { + "name": "punctuation.separator.namespace.js.jsx" + }, + "3": { + "name": "entity.other.attribute-name.js.jsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js.jsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js.jsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js.jsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js.jsx", + "match": "\\S+" + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/tsx.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/tsx.tmLanguage.json new file mode 100644 index 0000000000..de4f4aba36 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/tsx.tmLanguage.json @@ -0,0 +1,5876 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/33d8371c344f0b54746586313a939f742f9bcd3a", + "name": "tsx", + "scopeName": "source.tsx", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "include": "#shebang" + } + ], + "repository": { + "shebang": { + "name": "comment.line.shebang.tsx", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.tsx" + } + } + }, + "statements": { + "patterns": [ + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#label" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + }, + { + "name": "storage.modifier.tsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.tsx entity.name.function.tsx" + }, + "2": { + "name": "keyword.operator.definiteassignment.tsx" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.tsx variable.other.constant.tsx entity.name.function.tsx" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "keyword.operator.rest.tsx" + }, + "3": { + "name": "entity.name.function.tsx variable.language.this.tsx" + }, + "4": { + "name": "entity.name.function.tsx" + }, + "5": { + "name": "keyword.operator.optional.tsx" + } + } + }, + { + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "meta.definition.property.tsx entity.name.function.tsx" + }, + "2": { + "name": "keyword.operator.optional.tsx" + }, + "3": { + "name": "keyword.operator.definiteassignment.tsx" + } + } + }, + { + "name": "meta.definition.property.tsx variable.object.property.tsx", + "match": "\\#?[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.tsx", + "match": "\\?" + }, + { + "name": "keyword.operator.definiteassignment.tsx", + "match": "\\!" + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "keyword.operator.assignment.tsx" + } + }, + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "storage.modifier.tsx" + }, + "3": { + "name": "storage.modifier.tsx" + }, + "4": { + "name": "storage.modifier.async.tsx" + }, + "5": { + "name": "keyword.operator.new.tsx" + }, + "6": { + "name": "keyword.generator.asterisk.tsx" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + }, + { + "name": "meta.method.declaration.tsx", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "storage.modifier.tsx" + }, + "3": { + "name": "storage.modifier.tsx" + }, + "4": { + "name": "storage.modifier.async.tsx" + }, + "5": { + "name": "storage.type.property.tsx" + }, + "6": { + "name": "keyword.generator.asterisk.tsx" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + } + ] + }, + "object-literal-method-declaration": { + "name": "meta.method.declaration.tsx", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "storage.type.property.tsx" + }, + "3": { + "name": "keyword.generator.asterisk.tsx" + } + }, + "end": "(?=\\}|;|,)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + }, + { + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "storage.type.property.tsx" + }, + "3": { + "name": "keyword.generator.asterisk.tsx" + } + }, + "end": "(?=\\(|\\<)", + "patterns": [ + { + "include": "#method-declaration-name" + } + ] + } + ] + }, + "method-declaration-name": { + "begin": "(?x)(?=((\\b(?)", + "captures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "variable.parameter.tsx" + } + } + }, + { + "name": "meta.arrow.tsx", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])", + "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.tsx", + "begin": "(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.block.tsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.tsx" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-literal": { + "name": "meta.objectliteral.tsx", + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.tsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.tsx" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-member": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#object-literal-method-declaration" + }, + { + "name": "meta.object.member.tsx meta.object-literal.key.tsx", + "begin": "(?=\\[)", + "end": "(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#array-literal" + } + ] + }, + { + "name": "meta.object.member.tsx meta.object-literal.key.tsx", + "begin": "(?=[\\'\\\"\\`])", + "end": "(?=:)|((?<=[\\'\\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as)\\s+))))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + } + ] + }, + { + "name": "meta.object.member.tsx meta.object-literal.key.tsx", + "begin": "(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + }, + "1": { + "name": "entity.name.function.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.tsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)", + "captures": { + "1": { + "name": "variable.other.readwrite.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "match": "(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "meta.brace.round.tsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?<=\\>)", + "patterns": [ + { + "include": "#type-parameters" + } + ] + }, + { + "begin": "(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "meta.brace.round.tsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + }, + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.tsx" + } + }, + "end": "\\s*(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "patterns": [ + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "name": "meta.function-call.tsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + }, + { + "include": "#paren-expression" + } + ] + }, + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "end": "(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "name": "meta.function-call.tsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + } + ] + } + ] + }, + "function-call-target": { + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.tsx", + "match": "(\\#?[_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + "function-call-optionals": { + "patterns": [ + { + "name": "meta.function-call.tsx punctuation.accessor.optional.tsx", + "match": "\\?\\." + }, + { + "name": "meta.function-call.tsx keyword.operator.definiteassignment.tsx", + "match": "\\!" + } + ] + }, + "support-function-call-identifiers": { + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.tsx", + "match": "(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + "paren-expression-possibly-arrow-with-typeparameters": { + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.tsx" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + "expression-inside-possibly-arrow-parens": { + "patterns": [ + { + "include": "#expressionWithoutIdentifiers" + }, + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#decorator" + }, + { + "include": "#destructuring-parameter" + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "keyword.operator.rest.tsx" + }, + "3": { + "name": "entity.name.function.tsx variable.language.this.tsx" + }, + "4": { + "name": "entity.name.function.tsx" + }, + "5": { + "name": "keyword.operator.optional.tsx" + } + } + }, + { + "match": "(?x)(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.tsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.tsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.tsx", + "match": "<=|>=|<>|<|>" + }, + { + "match": "(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.logical.tsx" + }, + "2": { + "name": "keyword.operator.assignment.compound.tsx" + }, + "3": { + "name": "keyword.operator.arithmetic.tsx" + } + } + }, + { + "name": "keyword.operator.logical.tsx", + "match": "\\!|&&|\\|\\||\\?\\?" + }, + { + "name": "keyword.operator.bitwise.tsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.tsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.tsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.tsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.tsx", + "match": "%|\\*|/|-|\\+" + }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))", + "end": "(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))", + "endCaptures": { + "1": { + "name": "keyword.operator.assignment.compound.tsx" + }, + "2": { + "name": "keyword.operator.arithmetic.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, + { + "match": "(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.assignment.compound.tsx" + }, + "2": { + "name": "keyword.operator.arithmetic.tsx" + } + } + } + ] + }, + "typeof-operator": { + "begin": "(?:&|{\\?]|$|;|^\\s*$|(?:^\\s*(?:abstract|async|class|const|declare|enum|export|function|import|interface|let|module|namespace|return|type|var)\\b))", + "patterns": [ + { + "include": "#expression" + } + ] + }, + "literal": { + "patterns": [ + { + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.tsx", + "begin": "\\s*(\\[)", + "beginCaptures": { + "1": { + "name": "meta.brace.square.tsx" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.tsx", + "match": "\\b(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + }, + "3": { + "name": "support.variable.property.tsx" + }, + "4": { + "name": "support.constant.tsx" + } + } + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + }, + "3": { + "name": "entity.name.function.tsx" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + }, + "3": { + "name": "variable.other.constant.property.tsx" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + }, + "3": { + "name": "variable.other.property.tsx" + } + } + }, + { + "name": "variable.other.constant.tsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + }, + "3": { + "name": "variable.other.constant.object.property.tsx" + }, + "4": { + "name": "variable.other.object.property.tsx" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.tsx" + }, + "2": { + "name": "variable.other.object.tsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.tsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.tsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "parameter-type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.tsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?=[,)])|(?==[^>])", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.tsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "possibly-arrow-return-type": { + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "beginCaptures": { + "1": { + "name": "meta.arrow.tsx meta.return.type.arrow.tsx keyword.operator.type.annotation.tsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "contentName": "meta.arrow.tsx meta.return.type.arrow.tsx", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "arrow-return-type-body": { + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.tsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.tsx", + "match": "(?)" + } + ] + }, + "type-arguments": { + "name": "meta.type.parameters.tsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + "type-arguments-body": { + "patterns": [ + { + "match": "(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", + "captures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "keyword.operator.rest.tsx" + }, + "3": { + "name": "entity.name.function.tsx variable.language.this.tsx" + }, + "4": { + "name": "entity.name.function.tsx" + }, + "5": { + "name": "keyword.operator.optional.tsx" + } + } + }, + { + "match": "(?x)(?:(?)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + } + ] + }, + { + "name": "meta.type.constructor.tsx", + "begin": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.tsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?:\\?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.tsx", + "match": "(?)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.tsx punctuation.definition.typeparameters.end.tsx" + } + }, + "contentName": "meta.type.parameters.tsx", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "begin": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)", + "beginCaptures": { + "1": { + "name": "entity.name.type.tsx" + }, + "2": { + "name": "meta.type.parameters.tsx punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.tsx punctuation.definition.typeparameters.end.tsx" + } + }, + "contentName": "meta.type.parameters.tsx", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "entity.name.type.module.tsx" + }, + "2": { + "name": "punctuation.accessor.tsx" + }, + "3": { + "name": "punctuation.accessor.optional.tsx" + } + } + }, + { + "name": "entity.name.type.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "punctuation-comma": { + "name": "punctuation.separator.comma.tsx", + "match": "," + }, + "punctuation-semicolon": { + "name": "punctuation.terminator.statement.tsx", + "match": ";" + }, + "punctuation-accessor": { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "punctuation.accessor.optional.tsx" + } + } + }, + "string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template" + } + ] + }, + "qstring-double": { + "name": "string.quoted.double.tsx", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "end": "(\")|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.tsx" + }, + "2": { + "name": "invalid.illegal.newline.tsx" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "qstring-single": { + "name": "string.quoted.single.tsx", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "end": "(\\')|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.tsx" + }, + "2": { + "name": "invalid.illegal.newline.tsx" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.tsx", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "template": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.tsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.tsx" + }, + "2": { + "name": "punctuation.definition.string.template.begin.tsx" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.tsx" + } + }, + "patterns": [ + { + "include": "#template-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-call": { + "patterns": [ + { + "name": "string.template.tsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "end": "(?=`)", + "patterns": [ + { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.tagged-template.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#type-arguments" + } + ] + }, + { + "name": "string.template.tsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.tsx" + } + }, + "end": "(?=`)", + "patterns": [ + { + "include": "#type-arguments" + } + ] + } + ] + }, + "template-substitution-element": { + "name": "meta.template.expression.tsx", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.tsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ], + "contentName": "meta.embedded.line.tsx" + }, + "type-string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template-type" + } + ] + }, + "template-type": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.tsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.tsx" + }, + "2": { + "name": "punctuation.definition.string.template.begin.tsx" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.tsx" + } + }, + "patterns": [ + { + "include": "#template-type-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-type-substitution-element": { + "name": "meta.template.expression.tsx", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.tsx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.tsx" + } + }, + "patterns": [ + { + "include": "#type" + } + ], + "contentName": "meta.embedded.line.tsx" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.tsx", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "end": "(/)([dgimsuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.tsx" + }, + "2": { + "name": "keyword.other.tsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.tsx", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" + }, + { + "name": "keyword.operator.or.regexp", + "match": "\\|" + }, + { + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + } + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." + }, + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] + }, + "comment": { + "patterns": [ + { + "name": "comment.block.documentation.tsx", + "begin": "/\\*\\*(?!/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.tsx" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.tsx" + } + }, + "patterns": [ + { + "include": "#docblock" + } + ] + }, + { + "name": "comment.block.tsx", + "begin": "(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.tsx" + }, + "2": { + "name": "storage.type.internaldeclaration.tsx" + }, + "3": { + "name": "punctuation.decorator.internaldeclaration.tsx" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.tsx" + } + } + }, + { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.tsx" + }, + "2": { + "name": "comment.line.double-slash.tsx" + }, + "3": { + "name": "punctuation.definition.comment.tsx" + }, + "4": { + "name": "storage.type.internaldeclaration.tsx" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.tsx" + } + }, + "end": "(?=$)", + "contentName": "comment.line.double-slash.tsx" + } + ] + }, + "single-line-comment-consuming-line-ending": { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.tsx" + }, + "2": { + "name": "comment.line.double-slash.tsx" + }, + "3": { + "name": "punctuation.definition.comment.tsx" + }, + "4": { + "name": "storage.type.internaldeclaration.tsx" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.tsx" + } + }, + "end": "(?=^)", + "contentName": "comment.line.double-slash.tsx" + }, + "directives": { + "name": "comment.line.triple-slash.directive.tsx", + "begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.tsx" + } + }, + "end": "(?=$)", + "patterns": [ + { + "name": "meta.tag.tsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.tsx" + }, + "2": { + "name": "entity.name.tag.directive.tsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.tsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.tsx", + "match": "path|types|no-default-lib|lib|name" + }, + { + "name": "keyword.operator.assignment.tsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.tsx" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.tsx" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + }, + { + "match": "((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.tsx", + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.namespace.tsx" + }, + "3": { + "name": "punctuation.separator.namespace.tsx" + }, + "4": { + "name": "entity.name.tag.tsx" + }, + "5": { + "name": "support.class.component.tsx" + }, + "6": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.namespace.tsx" + }, + "3": { + "name": "punctuation.separator.namespace.tsx" + }, + "4": { + "name": "entity.name.tag.tsx" + }, + "5": { + "name": "support.class.component.tsx" + }, + "6": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "contentName": "meta.jsx.children.tsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.tsx", + "begin": "(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.tsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "3": { + "name": "entity.name.tag.namespace.tsx" + }, + "4": { + "name": "punctuation.separator.namespace.tsx" + }, + "5": { + "name": "entity.name.tag.tsx" + }, + "6": { + "name": "support.class.component.tsx" + }, + "7": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "patterns": [ + { + "begin": "(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.namespace.tsx" + }, + "3": { + "name": "punctuation.separator.namespace.tsx" + }, + "4": { + "name": "entity.name.tag.tsx" + }, + "5": { + "name": "support.class.component.tsx" + } + }, + "end": "(?=[/]?>)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-arguments" + }, + { + "include": "#jsx-tag-attributes" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n (?:([_$[:alpha:]][-_$[:alnum:].]*)(:))?\n ([_$[:alpha:]][-_$[:alnum:]]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.namespace.tsx" + }, + "2": { + "name": "punctuation.separator.namespace.tsx" + }, + "3": { + "name": "entity.other.attribute-name.tsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.tsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.tsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.tsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.tsx", + "match": "\\S+" + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/typescript.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/typescript.tmLanguage.json new file mode 100644 index 0000000000..9dcff85e4a --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/typescript.tmLanguage.json @@ -0,0 +1,5623 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/TypeScript-TmLanguage/blob/master/TypeScript.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/33d8371c344f0b54746586313a939f742f9bcd3a", + "name": "typescript", + "scopeName": "source.ts", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "include": "#shebang" + } + ], + "repository": { + "shebang": { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + }, + "statements": { + "patterns": [ + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#label" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + }, + { + "name": "storage.modifier.ts", + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts entity.name.function.ts" + }, + "2": { + "name": "keyword.operator.definiteassignment.ts" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts variable.other.constant.ts entity.name.function.ts" + } + }, + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "meta.definition.property.ts entity.name.function.ts" + }, + "2": { + "name": "keyword.operator.optional.ts" + }, + "3": { + "name": "keyword.operator.definiteassignment.ts" + } + } + }, + { + "name": "meta.definition.property.ts variable.object.property.ts", + "match": "\\#?[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.ts", + "match": "\\?" + }, + { + "name": "keyword.operator.definiteassignment.ts", + "match": "\\!" + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "keyword.operator.assignment.ts" + } + }, + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "storage.modifier.ts" + }, + "3": { + "name": "storage.modifier.ts" + }, + "4": { + "name": "storage.modifier.async.ts" + }, + "5": { + "name": "keyword.operator.new.ts" + }, + "6": { + "name": "keyword.generator.asterisk.ts" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + }, + { + "name": "meta.method.declaration.ts", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "storage.modifier.ts" + }, + "3": { + "name": "storage.modifier.ts" + }, + "4": { + "name": "storage.modifier.async.ts" + }, + "5": { + "name": "storage.type.property.ts" + }, + "6": { + "name": "keyword.generator.asterisk.ts" + } + }, + "end": "(?=\\}|;|,|$)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + } + ] + } + ] + }, + "object-literal-method-declaration": { + "name": "meta.method.declaration.ts", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "storage.type.property.ts" + }, + "3": { + "name": "keyword.generator.asterisk.ts" + } + }, + "end": "(?=\\}|;|,)|(?<=\\})", + "patterns": [ + { + "include": "#method-declaration-name" + }, + { + "include": "#function-body" + }, + { + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "storage.type.property.ts" + }, + "3": { + "name": "keyword.generator.asterisk.ts" + } + }, + "end": "(?=\\(|\\<)", + "patterns": [ + { + "include": "#method-declaration-name" + } + ] + } + ] + }, + "method-declaration-name": { + "begin": "(?x)(?=((\\b(?)", + "captures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "variable.parameter.ts" + } + } + }, + { + "name": "meta.arrow.ts", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "((?<=\\}|\\S)(?)|((?!\\{)(?=\\S)))(?!\\/[\\/\\*])", + "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.ts", + "begin": "(?:(?]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.block.ts" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.ts" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-literal": { + "name": "meta.objectliteral.ts", + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.ts" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.ts" + } + }, + "patterns": [ + { + "include": "#object-member" + } + ] + }, + "object-member": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#object-literal-method-declaration" + }, + { + "name": "meta.object.member.ts meta.object-literal.key.ts", + "begin": "(?=\\[)", + "end": "(?=:)|((?<=[\\]])(?=\\s*[\\(\\<]))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#array-literal" + } + ] + }, + { + "name": "meta.object.member.ts meta.object-literal.key.ts", + "begin": "(?=[\\'\\\"\\`])", + "end": "(?=:)|((?<=[\\'\\\"\\`])(?=((\\s*[\\(\\<,}])|(\\s+(as)\\s+))))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + } + ] + }, + { + "name": "meta.object.member.ts meta.object-literal.key.ts", + "begin": "(?x)(?=(\\b(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + }, + "1": { + "name": "entity.name.function.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:)", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$|\\/\\/|\\/\\*)", + "captures": { + "1": { + "name": "variable.other.readwrite.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "match": "(?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "meta.brace.round.ts" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "begin": "(?<=:)\\s*(async)?\\s*(?=\\<\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?<=\\>)", + "patterns": [ + { + "include": "#type-parameters" + } + ] + }, + { + "begin": "(?<=\\>)\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "meta.brace.round.ts" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + }, + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)(?!\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.ts" + } + }, + "end": "\\s*(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.ts" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "patterns": [ + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "name": "meta.function-call.ts", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?((<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\())", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + }, + { + "include": "#paren-expression" + } + ] + }, + { + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "end": "(?<=\\>)(?!(((([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "name": "meta.function-call.ts", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*)(\\s*\\??\\.\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*))*)|(\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*[\\{\\[\\(]\\s*$))", + "patterns": [ + { + "include": "#function-call-target" + } + ] + }, + { + "include": "#comment" + }, + { + "include": "#function-call-optionals" + }, + { + "include": "#type-arguments" + } + ] + } + ] + }, + "function-call-target": { + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.ts", + "match": "(\\#?[_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + "function-call-optionals": { + "patterns": [ + { + "name": "meta.function-call.ts punctuation.accessor.optional.ts", + "match": "\\?\\." + }, + { + "name": "meta.function-call.ts keyword.operator.definiteassignment.ts", + "match": "\\!" + } + ] + }, + "support-function-call-identifiers": { + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.ts", + "match": "(?:(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|(([\\&\\~\\^\\|]\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s+instanceof(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.)))|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?<=\\))", + "patterns": [ + { + "include": "#paren-expression-possibly-arrow-with-typeparameters" + } + ] + }, + { + "include": "#possibly-arrow-return-type" + } + ] + }, + "paren-expression-possibly-arrow-with-typeparameters": { + "patterns": [ + { + "include": "#type-parameters" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "patterns": [ + { + "include": "#expression-inside-possibly-arrow-parens" + } + ] + } + ] + }, + "expression-inside-possibly-arrow-parens": { + "patterns": [ + { + "include": "#expressionWithoutIdentifiers" + }, + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#decorator" + }, + { + "include": "#destructuring-parameter" + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": "(?x)(?:(?)", + "captures": { + "1": { + "name": "meta.brace.angle.ts" + }, + "2": { + "name": "storage.modifier.ts" + }, + "3": { + "name": "meta.brace.angle.ts" + } + } + }, + { + "name": "cast.expr.ts", + "begin": "(?:(?*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!)", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "cast.expr.ts", + "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", + "beginCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "end": "(\\>)", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "expression-operators": { + "patterns": [ + { + "name": "keyword.control.flow.ts", + "match": "(?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.ts", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.ts", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.ts", + "match": "<=|>=|<>|<|>" + }, + { + "match": "(?<=[_$[:alnum:]])(\\!)\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.logical.ts" + }, + "2": { + "name": "keyword.operator.assignment.compound.ts" + }, + "3": { + "name": "keyword.operator.arithmetic.ts" + } + } + }, + { + "name": "keyword.operator.logical.ts", + "match": "\\!|&&|\\|\\||\\?\\?" + }, + { + "name": "keyword.operator.bitwise.ts", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.ts", + "match": "--" + }, + { + "name": "keyword.operator.increment.ts", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.ts", + "match": "%|\\*|/|-|\\+" + }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(?:(/=)|(?:(/)(?![/*]))))", + "end": "(?:(/=)|(?:(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)))", + "endCaptures": { + "1": { + "name": "keyword.operator.assignment.compound.ts" + }, + "2": { + "name": "keyword.operator.arithmetic.ts" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, + { + "match": "(?<=[_$[:alnum:])\\]])\\s*(?:(/=)|(?:(/)(?![/*])))", + "captures": { + "1": { + "name": "keyword.operator.assignment.compound.ts" + }, + "2": { + "name": "keyword.operator.arithmetic.ts" + } + } + } + ] + }, + "typeof-operator": { + "begin": "(?:&|{\\?]|$|;|^\\s*$|(?:^\\s*(?:abstract|async|class|const|declare|enum|export|function|import|interface|let|module|namespace|return|type|var)\\b))", + "patterns": [ + { + "include": "#expression" + } + ] + }, + "literal": { + "patterns": [ + { + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.ts", + "begin": "\\s*(\\[)", + "beginCaptures": { + "1": { + "name": "meta.brace.square.ts" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.ts" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.ts", + "match": "\\b(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "support.variable.property.ts" + }, + "4": { + "name": "support.constant.ts" + } + } + }, + { + "match": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()\\'\\\"\\`]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "entity.name.function.ts" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.constant.property.ts" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.property.ts" + } + } + }, + { + "name": "variable.other.constant.ts", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n (\\#?[[:upper:]][_$[:digit:][:upper:]]*) |\n (\\#?[_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.constant.object.property.ts" + }, + "4": { + "name": "variable.other.object.property.ts" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*\\#?[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.ts" + }, + "2": { + "name": "variable.other.object.ts" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.ts", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.ts", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "parameter-type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.ts", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?=[,)])|(?==[^>])", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.ts", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "possibly-arrow-return-type": { + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "beginCaptures": { + "1": { + "name": "meta.arrow.ts meta.return.type.arrow.ts keyword.operator.type.annotation.ts" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "contentName": "meta.arrow.ts meta.return.type.arrow.ts", + "patterns": [ + { + "include": "#arrow-return-type-body" + } + ] + }, + "arrow-return-type-body": { + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.ts", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.ts", + "match": "(?)" + } + ] + }, + "type-arguments": { + "name": "meta.type.parameters.ts", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + "type-arguments-body": { + "patterns": [ + { + "match": "(?)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<([^<>]|\\<[^<>]+\\>)+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": "(?x)(?:(?)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + } + ] + }, + { + "name": "meta.type.constructor.ts", + "begin": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.ts", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?:\\?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.ts", + "match": "(?)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.ts punctuation.definition.typeparameters.end.ts" + } + }, + "contentName": "meta.type.parameters.ts", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "begin": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(<)", + "beginCaptures": { + "1": { + "name": "entity.name.type.ts" + }, + "2": { + "name": "meta.type.parameters.ts punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "meta.type.parameters.ts punctuation.definition.typeparameters.end.ts" + } + }, + "contentName": "meta.type.parameters.ts", + "patterns": [ + { + "include": "#type-arguments-body" + } + ] + }, + { + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "entity.name.type.module.ts" + }, + "2": { + "name": "punctuation.accessor.ts" + }, + "3": { + "name": "punctuation.accessor.optional.ts" + } + } + }, + { + "name": "entity.name.type.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "punctuation-comma": { + "name": "punctuation.separator.comma.ts", + "match": "," + }, + "punctuation-semicolon": { + "name": "punctuation.terminator.statement.ts", + "match": ";" + }, + "punctuation-accessor": { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + } + } + }, + "string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template" + } + ] + }, + "qstring-double": { + "name": "string.quoted.double.ts", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(\")|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "invalid.illegal.newline.ts" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "qstring-single": { + "name": "string.quoted.single.ts", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(\\')|((?:[^\\\\\\n])$)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "invalid.illegal.newline.ts" + } + }, + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.ts", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "template": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.ts", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.ts" + }, + "2": { + "name": "punctuation.definition.string.template.begin.ts" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.ts" + } + }, + "patterns": [ + { + "include": "#template-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-call": { + "patterns": [ + { + "name": "string.template.ts", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "end": "(?=`)", + "patterns": [ + { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?`)", + "patterns": [ + { + "include": "#support-function-call-identifiers" + }, + { + "name": "entity.name.function.tagged-template.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#type-arguments" + } + ] + }, + { + "name": "string.template.ts", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.ts" + } + }, + "end": "(?=`)", + "patterns": [ + { + "include": "#type-arguments" + } + ] + } + ] + }, + "template-substitution-element": { + "name": "meta.template.expression.ts", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.ts" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.ts" + } + }, + "patterns": [ + { + "include": "#expression" + } + ], + "contentName": "meta.embedded.line.ts" + }, + "type-string": { + "patterns": [ + { + "include": "#qstring-single" + }, + { + "include": "#qstring-double" + }, + { + "include": "#template-type" + } + ] + }, + "template-type": { + "patterns": [ + { + "include": "#template-call" + }, + { + "name": "string.template.ts", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)", + "beginCaptures": { + "1": { + "name": "entity.name.function.tagged-template.ts" + }, + "2": { + "name": "punctuation.definition.string.template.begin.ts" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.template.end.ts" + } + }, + "patterns": [ + { + "include": "#template-type-substitution-element" + }, + { + "include": "#string-character-escape" + } + ] + } + ] + }, + "template-type-substitution-element": { + "name": "meta.template.expression.ts", + "begin": "\\$\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.template-expression.begin.ts" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.template-expression.end.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ], + "contentName": "meta.embedded.line.ts" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.ts", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([dgimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(/)([dgimsuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "keyword.other.ts" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.ts", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" + }, + { + "name": "keyword.operator.or.regexp", + "match": "\\|" + }, + { + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + } + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." + }, + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] + }, + "comment": { + "patterns": [ + { + "name": "comment.block.documentation.ts", + "begin": "/\\*\\*(?!/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.ts" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.ts" + } + }, + "patterns": [ + { + "include": "#docblock" + } + ] + }, + { + "name": "comment.block.ts", + "begin": "(/\\*)(?:\\s*((@)internal)(?=\\s|(\\*/)))?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.ts" + }, + "2": { + "name": "storage.type.internaldeclaration.ts" + }, + "3": { + "name": "punctuation.decorator.internaldeclaration.ts" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.ts" + } + } + }, + { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.ts" + }, + "2": { + "name": "comment.line.double-slash.ts" + }, + "3": { + "name": "punctuation.definition.comment.ts" + }, + "4": { + "name": "storage.type.internaldeclaration.ts" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.ts" + } + }, + "end": "(?=$)", + "contentName": "comment.line.double-slash.ts" + } + ] + }, + "single-line-comment-consuming-line-ending": { + "begin": "(^[ \\t]+)?((//)(?:\\s*((@)internal)(?=\\s|$))?)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.ts" + }, + "2": { + "name": "comment.line.double-slash.ts" + }, + "3": { + "name": "punctuation.definition.comment.ts" + }, + "4": { + "name": "storage.type.internaldeclaration.ts" + }, + "5": { + "name": "punctuation.decorator.internaldeclaration.ts" + } + }, + "end": "(?=^)", + "contentName": "comment.line.double-slash.ts" + }, + "directives": { + "name": "comment.line.triple-slash.directive.ts", + "begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`)))+\\s*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + }, + "end": "(?=$)", + "patterns": [ + { + "name": "meta.tag.ts", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.ts" + }, + "2": { + "name": "entity.name.tag.directive.ts" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.ts" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.ts", + "match": "path|types|no-default-lib|lib|name" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.ts" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.ts" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + }, + { + "match": "((@)(?:[_$[:alpha:]][_$[:alnum:]]*))(?=\\s+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/vue-html.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/vue-html.tmLanguage.json new file mode 100644 index 0000000000..c1d8e11449 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/vue-html.tmLanguage.json @@ -0,0 +1,558 @@ +{ + "name": "vue-html", + "scopeName": "text.html.vue-html", + "fileTypes": [], + "uuid": "ca2e4260-5d62-45bf-8cf1-d8b5cc19c8f8", + "patterns": [ + { + "include": "source.vue#vue-interpolations" + }, + { + "name": "meta.tag.any.html", + "begin": "(<)([A-Z][a-zA-Z0-9:-]*)(?=[^>]*>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "support.class.component.html" + } + }, + "end": "(>)(<)(/)(\\2)(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + }, + "2": { + "name": "punctuation.definition.tag.begin.html meta.scope.between-tag-pair.html" + }, + "3": { + "name": "punctuation.definition.tag.begin.html" + }, + "4": { + "name": "support.class.component.html" + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.any.html", + "begin": "(<)([a-z][a-zA-Z0-9:-]*)(?=[^>]*>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + } + }, + "end": "(>)(<)(/)(\\2)(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + }, + "2": { + "name": "punctuation.definition.tag.begin.html meta.scope.between-tag-pair.html" + }, + "3": { + "name": "punctuation.definition.tag.begin.html" + }, + "4": { + "name": "entity.name.tag.html" + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.preprocessor.xml.html", + "begin": "(<\\?)(xml)", + "end": "(\\?>)", + "captures": { + "1": { + "name": "punctuation.definition.tag.html" + }, + "2": { + "name": "entity.name.tag.xml.html" + } + }, + "patterns": [ + { + "include": "#tag-generic-attribute" + }, + { + "include": "#string-double-quoted" + }, + { + "include": "#string-single-quoted" + } + ] + }, + { + "name": "comment.block.html", + "begin": "", + "captures": { + "0": { + "name": "punctuation.definition.comment.html" + } + } + }, + { + "name": "meta.tag.sgml.html", + "begin": "", + "captures": { + "0": { + "name": "punctuation.definition.tag.html" + } + }, + "patterns": [ + { + "name": "meta.tag.sgml.doctype.html", + "begin": "(?i:DOCTYPE)", + "end": "(?=>)", + "captures": { + "1": { + "name": "entity.name.tag.doctype.html" + } + }, + "patterns": [ + { + "name": "string.quoted.double.doctype.identifiers-and-DTDs.html", + "match": "\"[^\">]*\"" + } + ] + }, + { + "name": "constant.other.inline-data.html", + "begin": "\\[CDATA\\[", + "end": "]](?=>)" + }, + { + "name": "invalid.illegal.bad-comments-or-CDATA.html", + "match": "(\\s*)(?!--|>)\\S(\\s*)" + } + ] + }, + { + "name": "meta.tag.block.any.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.block.any.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.structure.any.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "captures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.structure.any.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.block.any.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.inline.any.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "name": "meta.tag.other.html", + "begin": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "include": "#entities" + }, + { + "name": "invalid.illegal.incomplete.html", + "match": "<>" + }, + { + "name": "invalid.illegal.bad-angle-bracket.html", + "match": "<" + } + ], + "repository": { + "entities": { + "patterns": [ + { + "name": "constant.character.entity.html", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.html" + }, + "3": { + "name": "punctuation.definition.entity.html" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.html", + "match": "&" + } + ] + }, + "string-double-quoted": { + "name": "string.quoted.double.html", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.vue#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + "string-single-quoted": { + "name": "string.quoted.single.html", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.vue#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + "tag-generic-attribute": { + "name": "entity.other.attribute-name.html", + "match": "(?<=[^=])\\b([a-zA-Z0-9:\\-_]+)" + }, + "tag-id-attribute": { + "name": "meta.attribute-with-value.id.html", + "begin": "\\b(id)\\b\\s*(=)", + "end": "(?!\\G)(?<='|\"|[^\\s<>/])", + "captures": { + "1": { + "name": "entity.other.attribute-name.id.html" + }, + "2": { + "name": "punctuation.separator.key-value.html" + } + }, + "patterns": [ + { + "name": "string.quoted.double.html", + "contentName": "meta.toc-list.id.html", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.vue#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + { + "name": "string.quoted.single.html", + "contentName": "meta.toc-list.id.html", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.vue#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + { + "name": "string.unquoted.html", + "match": "(?<==)(?:[^\\s<>/'\"]|/(?!>))+", + "captures": { + "0": { + "name": "meta.toc-list.id.html" + } + } + } + ] + }, + "tag-stuff": { + "patterns": [ + { + "include": "#vue-directives" + }, + { + "include": "#tag-id-attribute" + }, + { + "include": "#tag-generic-attribute" + }, + { + "include": "#string-double-quoted" + }, + { + "include": "#string-single-quoted" + }, + { + "include": "#unquoted-attribute" + } + ] + }, + "unquoted-attribute": { + "name": "string.unquoted.html", + "match": "(?<==)(?:[^\\s<>/'\"]|/(?!>))+" + }, + "vue-directives": { + "name": "meta.directive.vue", + "begin": "(?:\\b(v-)|(:|@|#))([a-zA-Z0-9\\-_]+)(?:\\:([a-zA-Z\\-_]+))?(?:\\.([a-zA-Z\\-_]+))*\\s*(=)", + "end": "(?<='|\")|(?=[\\s<>`])", + "captures": { + "1": { + "name": "entity.other.attribute-name.html" + }, + "2": { + "name": "punctuation.separator.key-value.html" + }, + "3": { + "name": "entity.other.attribute-name.html" + }, + "4": { + "name": "entity.other.attribute-name.html" + }, + "5": { + "name": "entity.other.attribute-name.html" + }, + "6": { + "name": "punctuation.separator.key-value.html" + } + }, + "patterns": [ + { + "name": "source.directive.vue", + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + }, + { + "name": "source.directive.vue", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + }, + { + "name": "source.directive.vue", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/vue.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/vue.tmLanguage.json new file mode 100644 index 0000000000..2cf9b075b1 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/vue.tmLanguage.json @@ -0,0 +1,1287 @@ +{ + "name": "vue", + "scopeName": "source.vue", + "fileTypes": [ + "vue" + ], + "uuid": "5512c10d-4cc5-434c-b8fc-53b912f55ab3", + "patterns": [ + { + "begin": "(<)(slim)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "contentName": "text.slim", + "patterns": [ + { + "include": "text.slim" + } + ] + } + ] + }, + { + "begin": "(<)(i18n)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "contentName": "source.json", + "patterns": [ + { + "include": "source.json" + } + ] + } + ] + }, + { + "begin": "(<)(docs)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "contentName": "text.html.markdown", + "patterns": [ + { + "include": "text.html.markdown" + } + ] + } + ] + }, + { + "name": "comment.block.html", + "begin": "", + "captures": { + "0": { + "name": "punctuation.definition.comment.html" + } + } + }, + { + "begin": "(<)(?=template.*[^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + } + }, + "end": "(/>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "begin": "(template)", + "beginCaptures": { + "1": { + "name": "entity.name.tag.template.html" + } + }, + "end": "(?=/>)", + "patterns": [ + { + "include": "#tag-stuff" + } + ] + } + ] + }, + { + "begin": "(<)(template)(?=[^>]*>[^/>]*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)" + } + ] + }, + { + "begin": "(<)(template)\\b(?=[^>]*lang=('jade'|\"jade\"|'pug'|\"pug\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.pug", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "text.pug" + } + ] + } + ] + }, + { + "begin": "(<)(template)\\b(?=[^>]*lang=('haml'|\"haml\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.haml", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "text.haml" + } + ] + } + ] + }, + { + "begin": "(<)(template)\\b(?=[^>]*lang=('slim'|\"slim\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.slim", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "text.slim" + } + ] + } + ] + }, + { + "begin": "(<)(template)\\b(?=[^>]*lang=('slm'|\"slm\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.jade.slm", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "text.jade.slm" + } + ] + } + ] + }, + { + "begin": "(<)(template)\\b(?=[^>]*lang=('liquid'|\"liquid\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.html.liquid", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "text.html.liquid" + } + ] + } + ] + }, + { + "begin": "(<)(template)(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + } + }, + "end": "^()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.template.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "text.html.vue-html", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=^)", + "patterns": [ + { + "include": "text.html.vue-html" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "(/>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "begin": "(<)(style)(?=[^>]*>[^/>]*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)" + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=('sass'|\"sass\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.sass", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.sass" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=('scss'|\"scss\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.css.scss", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.css.scss" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=('less'|\"less\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.css.less", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.css.less" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=('stylus'|\"stylus\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.stylus", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.stylus" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=('postcss'|\"postcss\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.css.postcss", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.css.postcss" + } + ] + } + ] + }, + { + "begin": "(<)(style)\\b(?=[^>]*lang=(['\"]sss['\"]))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.css.sugarss", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.css.sugarss" + } + ] + } + ] + }, + { + "begin": "(<)(style)(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.style.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.css", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.css" + } + ] + } + ] + }, + { + "begin": "(<)(script)\\b(?=[^>]*/>$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + } + }, + "end": "(/>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + } + ] + }, + { + "begin": "(<)(script)(?=[^>]*>[^/>]*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)" + } + ] + }, + { + "begin": "(<)(script)\\b(?=[^>]*lang=('ts'|\"ts\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.ts", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.ts" + } + ] + } + ] + }, + { + "begin": "(<)(script)\\b(?=[^>]*lang=('coffee'|\"coffee\"))(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.coffee", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.coffee" + } + ] + } + ] + }, + { + "begin": "(<)(script)(?![^/>]*/>\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + } + }, + "end": "()", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.script.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "include": "#tag-stuff" + }, + { + "contentName": "source.js", + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=)", + "patterns": [ + { + "include": "source.js" + } + ] + } + ] + } + ], + "repository": { + "entities": { + "patterns": [ + { + "name": "constant.character.entity.html", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.html" + }, + "3": { + "name": "punctuation.definition.entity.html" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.html", + "match": "&" + } + ] + }, + "string-double-quoted": { + "name": "string.quoted.double.html", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + "string-single-quoted": { + "name": "string.quoted.single.html", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + "tag-generic-attribute": { + "name": "entity.other.attribute-name.html", + "match": "\\b([a-zA-Z\\-:_]+)" + }, + "tag-id-attribute": { + "name": "meta.attribute-with-value.id.html", + "begin": "\\b(id)\\b\\s*(=)", + "end": "(?<='|\")", + "captures": { + "1": { + "name": "entity.other.attribute-name.id.html" + }, + "2": { + "name": "punctuation.separator.key-value.html" + } + }, + "patterns": [ + { + "name": "string.quoted.double.html", + "contentName": "meta.toc-list.id.html", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "#vue-interpolations" + }, + { + "include": "#entities" + } + ] + }, + { + "name": "string.quoted.single.html", + "contentName": "meta.toc-list.id.html", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "#vue-interpolations" + }, + { + "include": "#entities" + } + ] + } + ] + }, + "tag-stuff": { + "patterns": [ + { + "include": "#vue-directives" + }, + { + "include": "#tag-id-attribute" + }, + { + "include": "#tag-generic-attribute" + }, + { + "include": "#string-double-quoted" + }, + { + "include": "#string-single-quoted" + } + ] + }, + "vue-directives": { + "name": "meta.directive.vue", + "begin": "(?:\\b(v-)|(:|@|#))([a-zA-Z0-9\\-_]+)(?:\\:([a-zA-Z\\-_]+))?(?:\\.([a-zA-Z\\-_]+))*\\s*(=)", + "end": "(?<='|\")|(?=[\\s<>`])", + "captures": { + "1": { + "name": "entity.other.attribute-name.html" + }, + "2": { + "name": "punctuation.separator.key-value.html" + }, + "3": { + "name": "entity.other.attribute-name.html" + }, + "4": { + "name": "entity.other.attribute-name.html" + }, + "5": { + "name": "entity.other.attribute-name.html" + }, + "6": { + "name": "punctuation.separator.key-value.html" + } + }, + "patterns": [ + { + "name": "source.directive.vue", + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + }, + { + "name": "source.directive.vue", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + }, + { + "name": "source.directive.vue", + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.html" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + } + ] + }, + "vue-interpolations": { + "patterns": [ + { + "name": "expression.embedded.vue", + "begin": "\\{\\{\\{?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.generic.begin.html" + } + }, + "end": "\\}\\}\\}?", + "endCaptures": { + "0": { + "name": "punctuation.definition.generic.end.html" + } + }, + "patterns": [ + { + "include": "source.js#expression" + } + ] + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/languages/yaml.tmLanguage.json b/packages/frontend-shared/src/public/shiki/languages/yaml.tmLanguage.json new file mode 100644 index 0000000000..add1ba2424 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/languages/yaml.tmLanguage.json @@ -0,0 +1,621 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/textmate/yaml.tmbundle/blob/master/Syntaxes/YAML.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/textmate/yaml.tmbundle/commit/e54ceae3b719506dba7e481a77cea4a8b576ae46", + "name": "yaml", + "scopeName": "source.yaml", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#property" + }, + { + "include": "#directive" + }, + { + "match": "^---", + "name": "entity.other.document.begin.yaml" + }, + { + "match": "^\\.{3}", + "name": "entity.other.document.end.yaml" + }, + { + "include": "#node" + } + ], + "repository": { + "block-collection": { + "patterns": [ + { + "include": "#block-sequence" + }, + { + "include": "#block-mapping" + } + ] + }, + "block-mapping": { + "patterns": [ + { + "include": "#block-pair" + } + ] + }, + "block-node": { + "patterns": [ + { + "include": "#prototype" + }, + { + "include": "#block-scalar" + }, + { + "include": "#block-collection" + }, + { + "include": "#flow-scalar-plain-out" + }, + { + "include": "#flow-node" + } + ] + }, + "block-pair": { + "patterns": [ + { + "begin": "\\?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.key-value.begin.yaml" + } + }, + "end": "(?=\\?)|^ *(:)|(:)", + "endCaptures": { + "1": { + "name": "punctuation.separator.key-value.mapping.yaml" + }, + "2": { + "name": "invalid.illegal.expected-newline.yaml" + } + }, + "name": "meta.block-mapping.yaml", + "patterns": [ + { + "include": "#block-node" + } + ] + }, + { + "begin": "(?x)\n (?=\n (?x:\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] \\S\n )\n (\n [^\\s:]\n | : \\S\n | \\s+ (?![#\\s])\n )*\n \\s*\n :\n\t\t\t\t\t\t\t(\\s|$)\n )\n ", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n )\n ", + "patterns": [ + { + "include": "#flow-scalar-plain-out-implicit-type" + }, + { + "begin": "(?x)\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] \\S\n ", + "beginCaptures": { + "0": { + "name": "entity.name.tag.yaml" + } + }, + "contentName": "entity.name.tag.yaml", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n )\n ", + "name": "string.unquoted.plain.out.yaml" + } + ] + }, + { + "match": ":(?=\\s|$)", + "name": "punctuation.separator.key-value.mapping.yaml" + } + ] + }, + "block-scalar": { + "begin": "(?:(\\|)|(>))([1-9])?([-+])?(.*\\n?)", + "beginCaptures": { + "1": { + "name": "keyword.control.flow.block-scalar.literal.yaml" + }, + "2": { + "name": "keyword.control.flow.block-scalar.folded.yaml" + }, + "3": { + "name": "constant.numeric.indentation-indicator.yaml" + }, + "4": { + "name": "storage.modifier.chomping-indicator.yaml" + }, + "5": { + "patterns": [ + { + "include": "#comment" + }, + { + "match": ".+", + "name": "invalid.illegal.expected-comment-or-newline.yaml" + } + ] + } + }, + "end": "^(?=\\S)|(?!\\G)", + "patterns": [ + { + "begin": "^([ ]+)(?! )", + "end": "^(?!\\1|\\s*$)", + "name": "string.unquoted.block.yaml" + } + ] + }, + "block-sequence": { + "match": "(-)(?!\\S)", + "name": "punctuation.definition.block.sequence.item.yaml" + }, + "comment": { + "begin": "(?:(^[ \\t]*)|[ \\t]+)(?=#\\p{Print}*$)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.yaml" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.yaml" + } + }, + "end": "\\n", + "name": "comment.line.number-sign.yaml" + } + ] + }, + "directive": { + "begin": "^%", + "beginCaptures": { + "0": { + "name": "punctuation.definition.directive.begin.yaml" + } + }, + "end": "(?=$|[ \\t]+($|#))", + "name": "meta.directive.yaml", + "patterns": [ + { + "captures": { + "1": { + "name": "keyword.other.directive.yaml.yaml" + }, + "2": { + "name": "constant.numeric.yaml-version.yaml" + } + }, + "match": "\\G(YAML)[ \\t]+(\\d+\\.\\d+)" + }, + { + "captures": { + "1": { + "name": "keyword.other.directive.tag.yaml" + }, + "2": { + "name": "storage.type.tag-handle.yaml" + }, + "3": { + "name": "support.type.tag-prefix.yaml" + } + }, + "match": "(?x)\n \\G\n (TAG)\n (?:[ \\t]+\n ((?:!(?:[0-9A-Za-z\\-]*!)?))\n (?:[ \\t]+ (\n ! (?x: %[0-9A-Fa-f]{2} | [0-9A-Za-z\\-#;/?:@&=+$,_.!~*'()\\[\\]] )*\n | (?![,!\\[\\]{}]) (?x: %[0-9A-Fa-f]{2} | [0-9A-Za-z\\-#;/?:@&=+$,_.!~*'()\\[\\]] )+\n )\n )?\n )?\n " + }, + { + "captures": { + "1": { + "name": "support.other.directive.reserved.yaml" + }, + "2": { + "name": "string.unquoted.directive-name.yaml" + }, + "3": { + "name": "string.unquoted.directive-parameter.yaml" + } + }, + "match": "(?x) \\G (\\w+) (?:[ \\t]+ (\\w+) (?:[ \\t]+ (\\w+))? )?" + }, + { + "match": "\\S+", + "name": "invalid.illegal.unrecognized.yaml" + } + ] + }, + "flow-alias": { + "captures": { + "1": { + "name": "keyword.control.flow.alias.yaml" + }, + "2": { + "name": "punctuation.definition.alias.yaml" + }, + "3": { + "name": "variable.other.alias.yaml" + }, + "4": { + "name": "invalid.illegal.character.anchor.yaml" + } + }, + "match": "((\\*))([^\\s\\[\\]/{/},]+)([^\\s\\]},]\\S*)?" + }, + "flow-collection": { + "patterns": [ + { + "include": "#flow-sequence" + }, + { + "include": "#flow-mapping" + } + ] + }, + "flow-mapping": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.mapping.begin.yaml" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.mapping.end.yaml" + } + }, + "name": "meta.flow-mapping.yaml", + "patterns": [ + { + "include": "#prototype" + }, + { + "match": ",", + "name": "punctuation.separator.mapping.yaml" + }, + { + "include": "#flow-pair" + } + ] + }, + "flow-node": { + "patterns": [ + { + "include": "#prototype" + }, + { + "include": "#flow-alias" + }, + { + "include": "#flow-collection" + }, + { + "include": "#flow-scalar" + } + ] + }, + "flow-pair": { + "patterns": [ + { + "begin": "\\?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.key-value.begin.yaml" + } + }, + "end": "(?=[},\\]])", + "name": "meta.flow-pair.explicit.yaml", + "patterns": [ + { + "include": "#prototype" + }, + { + "include": "#flow-pair" + }, + { + "include": "#flow-node" + }, + { + "begin": ":(?=\\s|$|[\\[\\]{},])", + "beginCaptures": { + "0": { + "name": "punctuation.separator.key-value.mapping.yaml" + } + }, + "end": "(?=[},\\]])", + "patterns": [ + { + "include": "#flow-value" + } + ] + } + ] + }, + { + "begin": "(?x)\n (?=\n (?:\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] [^\\s[\\[\\]{},]]\n )\n (\n [^\\s:[\\[\\]{},]]\n | : [^\\s[\\[\\]{},]]\n | \\s+ (?![#\\s])\n )*\n \\s*\n :\n\t\t\t\t\t\t\t(\\s|$)\n )\n ", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n | \\s* : [\\[\\]{},]\n | \\s* [\\[\\]{},]\n )\n ", + "name": "meta.flow-pair.key.yaml", + "patterns": [ + { + "include": "#flow-scalar-plain-in-implicit-type" + }, + { + "begin": "(?x)\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] [^\\s[\\[\\]{},]]\n ", + "beginCaptures": { + "0": { + "name": "entity.name.tag.yaml" + } + }, + "contentName": "entity.name.tag.yaml", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n | \\s* : [\\[\\]{},]\n | \\s* [\\[\\]{},]\n )\n ", + "name": "string.unquoted.plain.in.yaml" + } + ] + }, + { + "include": "#flow-node" + }, + { + "begin": ":(?=\\s|$|[\\[\\]{},])", + "captures": { + "0": { + "name": "punctuation.separator.key-value.mapping.yaml" + } + }, + "end": "(?=[},\\]])", + "name": "meta.flow-pair.yaml", + "patterns": [ + { + "include": "#flow-value" + } + ] + } + ] + }, + "flow-scalar": { + "patterns": [ + { + "include": "#flow-scalar-double-quoted" + }, + { + "include": "#flow-scalar-single-quoted" + }, + { + "include": "#flow-scalar-plain-in" + } + ] + }, + "flow-scalar-double-quoted": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.yaml" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.yaml" + } + }, + "name": "string.quoted.double.yaml", + "patterns": [ + { + "match": "\\\\([0abtnvfre \"/\\\\N_Lp]|x\\d\\d|u\\d{4}|U\\d{8})", + "name": "constant.character.escape.yaml" + }, + { + "match": "\\\\\\n", + "name": "constant.character.escape.double-quoted.newline.yaml" + } + ] + }, + "flow-scalar-plain-in": { + "patterns": [ + { + "include": "#flow-scalar-plain-in-implicit-type" + }, + { + "begin": "(?x)\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] [^\\s[\\[\\]{},]]\n ", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n | \\s* : [\\[\\]{},]\n | \\s* [\\[\\]{},]\n )\n ", + "name": "string.unquoted.plain.in.yaml" + } + ] + }, + "flow-scalar-plain-in-implicit-type": { + "patterns": [ + { + "captures": { + "1": { + "name": "constant.language.null.yaml" + }, + "2": { + "name": "constant.language.boolean.yaml" + }, + "3": { + "name": "constant.numeric.integer.yaml" + }, + "4": { + "name": "constant.numeric.float.yaml" + }, + "5": { + "name": "constant.other.timestamp.yaml" + }, + "6": { + "name": "constant.language.value.yaml" + }, + "7": { + "name": "constant.language.merge.yaml" + } + }, + "match": "(?x)\n (?x:\n (null|Null|NULL|~)\n | (y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)\n | (\n (?:\n [-+]? 0b [0-1_]+ # (base 2)\n | [-+]? 0 [0-7_]+ # (base 8)\n | [-+]? (?: 0|[1-9][0-9_]*) # (base 10)\n | [-+]? 0x [0-9a-fA-F_]+ # (base 16)\n | [-+]? [1-9] [0-9_]* (?: :[0-5]?[0-9])+ # (base 60)\n )\n )\n | (\n (?x:\n [-+]? (?: [0-9] [0-9_]*)? \\. [0-9.]* (?: [eE] [-+] [0-9]+)? # (base 10)\n | [-+]? [0-9] [0-9_]* (?: :[0-5]?[0-9])+ \\. [0-9_]* # (base 60)\n | [-+]? \\. (?: inf|Inf|INF) # (infinity)\n | \\. (?: nan|NaN|NAN) # (not a number)\n )\n )\n | (\n (?x:\n \\d{4} - \\d{2} - \\d{2} # (y-m-d)\n | \\d{4} # (year)\n - \\d{1,2} # (month)\n - \\d{1,2} # (day)\n (?: [Tt] | [ \\t]+) \\d{1,2} # (hour)\n : \\d{2} # (minute)\n : \\d{2} # (second)\n (?: \\.\\d*)? # (fraction)\n (?:\n (?:[ \\t]*) Z\n | [-+] \\d{1,2} (?: :\\d{1,2})?\n )? # (time zone)\n )\n )\n | (=)\n | (<<)\n )\n (?:\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n | \\s* : [\\[\\]{},]\n | \\s* [\\[\\]{},]\n )\n )\n " + } + ] + }, + "flow-scalar-plain-out": { + "patterns": [ + { + "include": "#flow-scalar-plain-out-implicit-type" + }, + { + "begin": "(?x)\n [^\\s[-?:,\\[\\]{}#&*!|>'\"%@`]]\n | [?:-] \\S\n ", + "end": "(?x)\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n )\n ", + "name": "string.unquoted.plain.out.yaml" + } + ] + }, + "flow-scalar-plain-out-implicit-type": { + "patterns": [ + { + "captures": { + "1": { + "name": "constant.language.null.yaml" + }, + "2": { + "name": "constant.language.boolean.yaml" + }, + "3": { + "name": "constant.numeric.integer.yaml" + }, + "4": { + "name": "constant.numeric.float.yaml" + }, + "5": { + "name": "constant.other.timestamp.yaml" + }, + "6": { + "name": "constant.language.value.yaml" + }, + "7": { + "name": "constant.language.merge.yaml" + } + }, + "match": "(?x)\n (?x:\n (null|Null|NULL|~)\n | (y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)\n | (\n (?:\n [-+]? 0b [0-1_]+ # (base 2)\n | [-+]? 0 [0-7_]+ # (base 8)\n | [-+]? (?: 0|[1-9][0-9_]*) # (base 10)\n | [-+]? 0x [0-9a-fA-F_]+ # (base 16)\n | [-+]? [1-9] [0-9_]* (?: :[0-5]?[0-9])+ # (base 60)\n )\n )\n | (\n (?x:\n [-+]? (?: [0-9] [0-9_]*)? \\. [0-9.]* (?: [eE] [-+] [0-9]+)? # (base 10)\n | [-+]? [0-9] [0-9_]* (?: :[0-5]?[0-9])+ \\. [0-9_]* # (base 60)\n | [-+]? \\. (?: inf|Inf|INF) # (infinity)\n | \\. (?: nan|NaN|NAN) # (not a number)\n )\n )\n | (\n (?x:\n \\d{4} - \\d{2} - \\d{2} # (y-m-d)\n | \\d{4} # (year)\n - \\d{1,2} # (month)\n - \\d{1,2} # (day)\n (?: [Tt] | [ \\t]+) \\d{1,2} # (hour)\n : \\d{2} # (minute)\n : \\d{2} # (second)\n (?: \\.\\d*)? # (fraction)\n (?:\n (?:[ \\t]*) Z\n | [-+] \\d{1,2} (?: :\\d{1,2})?\n )? # (time zone)\n )\n )\n | (=)\n | (<<)\n )\n (?x:\n (?=\n \\s* $\n | \\s+ \\#\n | \\s* : (\\s|$)\n )\n )\n " + } + ] + }, + "flow-scalar-single-quoted": { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.yaml" + } + }, + "end": "'(?!')", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.yaml" + } + }, + "name": "string.quoted.single.yaml", + "patterns": [ + { + "match": "''", + "name": "constant.character.escape.single-quoted.yaml" + } + ] + }, + "flow-sequence": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.sequence.begin.yaml" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.sequence.end.yaml" + } + }, + "name": "meta.flow-sequence.yaml", + "patterns": [ + { + "include": "#prototype" + }, + { + "match": ",", + "name": "punctuation.separator.sequence.yaml" + }, + { + "include": "#flow-pair" + }, + { + "include": "#flow-node" + } + ] + }, + "flow-value": { + "patterns": [ + { + "begin": "\\G(?![},\\]])", + "end": "(?=[},\\]])", + "name": "meta.flow-pair.value.yaml", + "patterns": [ + { + "include": "#flow-node" + } + ] + } + ] + }, + "node": { + "patterns": [ + { + "include": "#block-node" + } + ] + }, + "property": { + "begin": "(?=!|&)", + "end": "(?!\\G)", + "name": "meta.property.yaml", + "patterns": [ + { + "captures": { + "1": { + "name": "keyword.control.property.anchor.yaml" + }, + "2": { + "name": "punctuation.definition.anchor.yaml" + }, + "3": { + "name": "entity.name.type.anchor.yaml" + }, + "4": { + "name": "invalid.illegal.character.anchor.yaml" + } + }, + "match": "\\G((&))([^\\s\\[\\]/{/},]+)(\\S+)?" + }, + { + "match": "(?x)\n \\G\n (?:\n ! < (?: %[0-9A-Fa-f]{2} | [0-9A-Za-z\\-#;/?:@&=+$,_.!~*'()\\[\\]] )+ >\n | (?:!(?:[0-9A-Za-z\\-]*!)?) (?: %[0-9A-Fa-f]{2} | [0-9A-Za-z\\-#;/?:@&=+$_.~*'()] )+\n | !\n )\n (?=\\ |\\t|$)\n ", + "name": "storage.type.tag-handle.yaml" + }, + { + "match": "\\S+", + "name": "invalid.illegal.tag-handle.yaml" + } + ] + }, + "prototype": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#property" + } + ] + } + } +} diff --git a/packages/frontend-shared/src/public/shiki/themes/.gitignore b/packages/frontend-shared/src/public/shiki/themes/.gitignore new file mode 100644 index 0000000000..e66d0445f7 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/themes/.gitignore @@ -0,0 +1 @@ +cypress.theme.json \ No newline at end of file diff --git a/packages/frontend-shared/src/public/shiki/themes/ReadMe.md b/packages/frontend-shared/src/public/shiki/themes/ReadMe.md new file mode 100644 index 0000000000..c156bbf4ca --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/themes/ReadMe.md @@ -0,0 +1,16 @@ +# Theme folder for shiki + +The theme here is meant to be generated + +## To Transform + +To transform `cypress.theme.template.json` into `cypress.theme.json` use the command `yarn generate-shiki-theme`. +This command is run as part of the build process and should not need to be run manually unless you are changing the template. + +## How the template works + +In the template, the colors are called by their name in windi prefixed by a dash. + +For example if you have `-jade-500` in the template, it will be replaced by `#00814D`, Jade 500 in the generated theme. + +All colors from the theme are available \ No newline at end of file diff --git a/packages/frontend-shared/src/public/shiki/themes/cypress.theme.template.json b/packages/frontend-shared/src/public/shiki/themes/cypress.theme.template.json new file mode 100644 index 0000000000..1c4b241710 --- /dev/null +++ b/packages/frontend-shared/src/public/shiki/themes/cypress.theme.template.json @@ -0,0 +1,590 @@ +{ + "name": "cypress", + "type": "light", + "tokenColors": [ + { + "settings": { + "foreground": "-gray-800" + } + }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "emphasis", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "strong", + "settings": { + "fontStyle": "bold" + } + }, + { + "scope": "meta.diff.header", + "settings": { + "foreground": "-indigo-800" + } + }, + { + "scope": "comment", + "settings": { + "foreground": "-gray-500" + } + }, + { + "scope": "constant.language", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": [ + "constant.numeric", + "variable.other.enummember", + "keyword.operator.plus.exponent", + "keyword.operator.minus.exponent" + ], + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": "constant.regexp", + "settings": { + "foreground": "-red-900" + } + }, + { + "name": "css tags in selectors, xml tags", + "scope": "entity.name.tag", + "settings": { + "foreground": "-red-800" + } + }, + { + "scope": "entity.name.selector", + "settings": { + "foreground": "-red-800" + } + }, + { + "scope": "entity.other.attribute-name", + "settings": { + "foreground": "-red-500" + } + }, + { + "scope": [ + "entity.other.attribute-name.class.css", + "entity.other.attribute-name.class.mixin.css", + "entity.other.attribute-name.id.css", + "entity.other.attribute-name.parent-selector.css", + "entity.other.attribute-name.pseudo-class.css", + "entity.other.attribute-name.pseudo-element.css", + "source.css.less entity.other.attribute-name.id", + "entity.other.attribute-name.scss" + ], + "settings": { + "foreground": "-red-800" + } + }, + { + "scope": "invalid", + "settings": { + "foreground": "-red-500" + } + }, + { + "scope": "markup.underline", + "settings": { + "fontStyle": "underline" + } + }, + { + "scope": "markup.bold", + "settings": { + "fontStyle": "bold", + "foreground": "-indigo-800" + } + }, + { + "scope": "markup.heading", + "settings": { + "fontStyle": "bold", + "foreground": "-red-800" + } + }, + { + "scope": "markup.italic", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "markup.inserted", + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": "markup.deleted", + "settings": { + "foreground": "-red-500" + } + }, + { + "scope": "markup.changed", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": [ + "punctuation.definition.quote.begin.markdown", + "punctuation.definition.list.begin.markdown" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "markup.inline.raw", + "settings": { + "foreground": "-red-800" + } + }, + { + "name": "brackets of XML/HTML tags", + "scope": "punctuation.definition.tag", + "settings": { + "foreground": "-red-800" + } + }, + { + "scope": [ + "meta.preprocessor", + "entity.name.function.preprocessor" + ], + "settings": { + "foreground": "-orange-500" + } + }, + { + "scope": "meta.preprocessor.string", + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": "meta.preprocessor.numeric", + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": "meta.structure.dictionary.key.python", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "storage", + "settings": { + "foreground": "-orange-500" + } + }, + { + "scope": "storage.type", + "settings": { + "foreground": "-orange-500" + } + }, + { + "scope": [ + "storage.modifier", + "keyword.operator.noexcept" + ], + "settings": { + "foreground": "-orange-500" + } + }, + { + "scope": [ + "string", + "meta.embedded.assembly" + ], + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": [ + "string.comment.buffered.block.pug", + "string.quoted.pug", + "string.interpolated.pug", + "string.unquoted.plain.in.yaml", + "string.unquoted.plain.out.yaml", + "string.unquoted.block.yaml", + "string.quoted.single.yaml", + "string.quoted.double.xml", + "string.quoted.single.xml", + "string.unquoted.cdata.xml", + "string.quoted.double.html", + "string.quoted.single.html", + "string.unquoted.html", + "string.quoted.single.handlebars", + "string.quoted.double.handlebars" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "string.regexp", + "settings": { + "foreground": "-red-800" + } + }, + { + "name": "String interpolation", + "scope": [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "name": "Reset JavaScript string interpolation expression", + "scope": [ + "meta.template.expression" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": [ + "support.type.vendored.property-name", + "support.type.property-name", + "variable.css", + "variable.scss", + "variable.other.less", + "source.coffee.embedded" + ], + "settings": { + "foreground": "-red-500" + } + }, + { + "scope": [ + "support.type.property-name.json" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "keyword", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "keyword.control", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "keyword.operator", + "settings": { + "foreground": "-gray-800" + } + }, + { + "scope": [ + "keyword.operator.new", + "keyword.operator.expression", + "keyword.operator.cast", + "keyword.operator.sizeof", + "keyword.operator.alignof", + "keyword.operator.typeid", + "keyword.operator.alignas", + "keyword.operator.instanceof", + "keyword.operator.logical.python", + "keyword.operator.wordlike" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "keyword.other.unit", + "settings": { + "foreground": "-jade-500" + } + }, + { + "scope": [ + "punctuation.section.embedded.begin.php", + "punctuation.section.embedded.end.php" + ], + "settings": { + "foreground": "-red-800" + } + }, + { + "scope": "support.function.git-rebase", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "constant.sha.git-rebase", + "settings": { + "foreground": "-jade-500" + } + }, + { + "name": "coloring of the Java import and package identifiers", + "scope": [ + "storage.modifier.import.java", + "variable.language.wildcard.java", + "storage.modifier.package.java" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "name": "this.self", + "scope": "variable.language", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "name": "Function declarations", + "scope": [ + "entity.name.function", + "support.function", + "support.constant.handlebars", + "source.powershell variable.other.member", + "entity.name.operator.custom-literal" + ], + "settings": { + "foreground": "-orange-500" + } + }, + { + "name": "Types declaration and references", + "scope": [ + "meta.return-type", + "support.class", + "support.type", + "entity.name.type", + "entity.name.namespace", + "entity.other.attribute", + "entity.name.scope-resolution", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy" + ], + "settings": { + "foreground": "-magenta-500" + } + }, + { + "name": "Types declaration and references, TS grammar specific", + "scope": [ + "meta.type.cast.expr", + "meta.type.new.expr", + "support.constant.math", + "support.constant.dom", + "support.constant.json", + "entity.other.inherited-class" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "name": "Control flow / Special keywords", + "scope": [ + "keyword.control", + "source.cpp keyword.operator.new", + "source.cpp keyword.operator.delete", + "keyword.other.using", + "keyword.other.operator", + "entity.name.operator" + ], + "settings": { + "foreground": "-purple-500" + } + }, + { + "name": "Variable and parameter name", + "scope": [ + "variable", + "meta.definition.variable.name", + "support.variable", + "entity.name.variable", + "constant.other.placeholder" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "name": "Constants and enums", + "scope": [ + "variable.other.constant", + "variable.other.enummember" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "name": "Object keys, TS grammar specific", + "scope": [ + "meta.object-literal.key" + ], + "settings": { + "foreground": "-gray-800" + } + }, + { + "name": "CSS property value", + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "-indigo-500" + } + }, + { + "name": "Regular expression groups", + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "-orange-500" + } + }, + { + "name": "Punctuation tokens", + "scope": [ + "punctuation" + ], + "settings": { + "foreground": "-gray-500" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "-magenta-500" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "-gray-800" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "-red-400" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "-indigo-500" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "-red-400" + } + }, + { + "scope": "entity.name.label", + "settings": { + "foreground": "-gray-800" + } + } + ] +} diff --git a/packages/frontend-shared/src/styles/normalize.scss b/packages/frontend-shared/src/styles/normalize.scss new file mode 100644 index 0000000000..eec7e90ead --- /dev/null +++ b/packages/frontend-shared/src/styles/normalize.scss @@ -0,0 +1,825 @@ +/** + * Tailwind's Preflight Style Reset + * https://tailwindcss.com/docs/preflight + * + * Why is this here? + * 1. Tailwind doesn't publish their style reset (which is + * derived from modern-normalize). + * 2. WindiCSS's version of this doesn't work with third-party + * DOM elements that it can't extract. + */ + + /*! tailwindcss v2.2.16 | MIT License | https://tailwindcss.com */ +/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ +@use 'modern-normalize/modern-normalize.css'; + +/* +Document +======== +*/ + +/** +Use a better box model (opinionated). +*/ + +*, +::before, +::after { + box-sizing: border-box; +} + +/** +Use a more readable tab size (opinionated). +*/ + +html { + -moz-tab-size: 4; + tab-size: 4; +} + +/** +1. Correct the line height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +*/ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* +Sections +======== +*/ + +/** +Remove the margin in all browsers. +*/ + +body { + margin: 0; +} + +/** +Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) +*/ + +body { + font-family: + system-ui, + -apple-system, /* Firefox supports this but not yet `system-ui` */ + 'Segoe UI', + Roboto, + Helvetica, + Arial, + sans-serif, + 'Apple Color Emoji', + 'Segoe UI Emoji'; +} + +/* +Grouping content +================ +*/ + +/** +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ +} + +/* +Text-level semantics +==================== +*/ + +/** +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr[title] { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/** +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/** +1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) +2. Correct the odd 'em' font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: + ui-monospace, + SFMono-Regular, + Consolas, + 'Liberation Mono', + Menlo, + monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/** +Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +Tabular data +============ +*/ + +/** +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ +} + +/* +Forms +===== +*/ + +/** +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** +Remove the inheritance of text transform in Edge and Firefox. +1. Remove the inheritance of text transform in Firefox. +*/ + +button, +select { /* 1 */ + text-transform: none; +} + +/** +Correct the inability to style clickable types in iOS and Safari. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; +} + +/** +Remove the inner border and padding in Firefox. +*/ + +::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** +Restore the focus styles unset by the previous rule. +*/ + +:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** +Remove the additional ':invalid' styles in Firefox. +See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737 +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/** +Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. +*/ + +legend { + padding: 0; +} + +/** +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/** +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/** +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to 'inherit' in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Interactive +=========== +*/ + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/** + * Manually forked from SUIT CSS Base: https://github.com/suitcss/base + * A thin layer on top of normalize.css that provides a starting point more + * suitable for web applications. + */ + +/** + * Removes the default spacing and border for appropriate elements. + */ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +button { + background-color: transparent; + background-image: none; +} + +fieldset { + margin: 0; + padding: 0; +} + +ol, +ul { + list-style: none; + margin: 0; + padding: 0; +} + +/** + * Tailwind custom reset styles + */ + +/** + * 1. Use the user's configured `sans` font-family (with Tailwind's default + * sans-serif font stack as a fallback) as a sane default. + * 2. Use Tailwind's default "normal" line-height so the user isn't forced + * to override it to ensure consistency even when using the default theme. + */ + +html { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 1 */ + line-height: 1.5; /* 2 */ +} + +/** + * Inherit font-family and line-height from `html` so users can set them as + * a class directly on the `html` element. + */ + +body { + font-family: inherit; + line-height: inherit; +} + +/** + * 1. Prevent padding and border from affecting element width. + * + * We used to set this in the html element and inherit from + * the parent element for everything else. This caused issues + * in shadow-dom-enhanced elements like
where the content + * is wrapped by a div with box-sizing set to `content-box`. + * + * https://github.com/mozdevs/cssremedy/issues/4 + * + * + * 2. Allow adding a border to an element by just adding a border-width. + * + * By default, the way the browser specifies that an element should have no + * border is by setting it's border-style to `none` in the user-agent + * stylesheet. + * + * In order to easily add borders to elements by just setting the `border-width` + * property, we change the default border-style for all elements to `solid`, and + * use border-width to hide them instead. This way our `border` utilities only + * need to set the `border-width` property instead of the entire `border` + * shorthand, making our border utilities much more straightforward to compose. + * + * https://github.com/tailwindcss/tailwindcss/pull/116 + */ + +*, +::before, +::after { + box-sizing: border-box; /* 1 */ + border-width: 0; /* 2 */ + border-style: solid; /* 2 */ + border-color: currentColor; /* 2 */ +} + +/* + * Ensure horizontal rules are visible by default + */ + +hr { + border-top-width: 1px; +} + +/** + * Undo the `border-style: none` reset that Normalize applies to images so that + * our `border-{width}` utilities have the expected effect. + * + * The Normalize reset is unnecessary for us since we default the border-width + * to 0 on all elements. + * + * https://github.com/tailwindcss/tailwindcss/issues/362 + */ + +img { + border-style: solid; +} + +textarea { + resize: vertical; +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + color: #9ca3af; +} + +button, +[role="button"] { + cursor: pointer; +} + +/** + * Override legacy focus reset from Normalize with modern Firefox focus styles. + * + * This is actually an improvement over the new defaults in Firefox in our testing, + * as it triggers the better focus styles even for links, which still use a dotted + * outline in Firefox by default. + */ + +:-moz-focusring { + outline: auto; +} + +table { + border-collapse: collapse; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/** + * Reset links to optimize for opt-in styling instead of + * opt-out. + */ + +a { + color: inherit; + text-decoration: inherit; +} + +/** + * Reset form element properties that are easy to forget to + * style explicitly so you don't inadvertently introduce + * styles that deviate from your design system. These styles + * supplement a partial reset that is already applied by + * normalize.css. + */ + +button, +input, +optgroup, +select, +textarea { + padding: 0; + line-height: inherit; + color: inherit; +} + +/** + * Use the configured 'mono' font family for elements that + * are expected to be rendered with a monospace font, falling + * back to the system monospace stack if there is no configured + * 'mono' font family. + */ + +pre, +code, +kbd, +samp { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +/** + * 1. Make replaced elements `display: block` by default as that's + * the behavior you want almost all of the time. Inspired by + * CSS Remedy, with `svg` added as well. + * + * https://github.com/mozdevs/cssremedy/issues/14 + * + * 2. Add `vertical-align: middle` to align replaced elements more + * sensibly by default when overriding `display` by adding a + * utility like `inline`. + * + * This can trigger a poorly considered linting error in some + * tools but is included by design. + * + * https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210 + */ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/** + * Constrain images and videos to the parent width and preserve + * their intrinsic aspect ratio. + * + * https://github.com/mozdevs/cssremedy/issues/14 + */ + +img, +video { + max-width: 100%; + height: auto; +} + +/** + * Ensure the default browser behavior of the `hidden` attribute. + */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-opacity: 1; + border-color: rgba(229, 231, 235, var(--tw-border-opacity)); +} + + +/* +* Global Resets +* ------------------------- +*/ + +// Input Resets +// Taken from Tailwind CSS Forms -- a plugin for tailwind. +// We could probably add these into WindiCSS directly +// https://github.com/tailwindlabs/tailwindcss-forms + +[multiple], +[type=date], +[type=datetime-local], +[type=email], +[type=month], +[type=number], +[type=password], +[type=search], +[type=tel], +[type=text], +[type=time], +[type=url], +[type=week], +select, +textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + border-radius: 0; + padding-top: 0.35rem; + padding-bottom: 0.35rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + font-size: 1rem; + line-height: 1.25rem; +} + +[multiple]:focus, +[type=date]:focus, +[type=datetime-local]:focus, +[type=email]:focus, +[type=month]:focus, +[type=number]:focus, +[type=password]:focus, +[type=search]:focus, +[type=tel]:focus, +[type=text]:focus, +[type=time]:focus, +[type=url]:focus, +[type=week]:focus, +select:focus, +textarea:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty, ); + /*!*/ + /*!*/ + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + border-color: #2563eb; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + color: #6b7280; + opacity: 1; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #6b7280; + opacity: 1; +} + +input::placeholder, +textarea::placeholder { + color: #6b7280; + opacity: 1; +} + +::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +::-webkit-date-and-time-value { + min-height: 1.5em; +} + +select { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right .5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + color-adjust: exact; +} + +[multiple] { + background-image: initial; + background-position: initial; + background-repeat: unset; + background-size: initial; + padding-right: .75rem; + -webkit-print-color-adjust: unset; + color-adjust: unset; +} + +[type=checkbox], +[type=radio] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + -webkit-print-color-adjust: exact; + color-adjust: exact; + display: inline-block; + vertical-align: middle; + background-origin: border-box; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #2563eb; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; +} + +[type=checkbox] { + border-radius: 0; +} + +[type=radio] { + border-radius: 100%; +} + +[type=checkbox]:focus, +[type=radio]:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty); + --tw-ring-offset-width: 2px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); +} + +[type=checkbox]:checked, +[type=radio]:checked { + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +[type=checkbox]:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); +} + +[type=radio]:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); +} + +[type=checkbox]:checked:focus, +[type=checkbox]:checked:hover, +[type=radio]:checked:focus, +[type=radio]:checked:hover { + border-color: transparent; + background-color: currentColor; +} + +[type=checkbox]:indeterminate { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +[type=checkbox]:indeterminate:focus, +[type=checkbox]:indeterminate:hover { + border-color: transparent; + background-color: currentColor; +} + +[type=file] { + background: unset; + border-color: inherit; + border-width: 0; + border-radius: 0; + padding: 0; + font-size: unset; + line-height: inherit; +} + +[type=file]:focus { + outline: 1px auto -webkit-focus-ring-color; +} + + +input[type="search"].dark { + background: #222; + color: #fff; +} + +input[type="search"].light { + background: #fff; + color: #222; +} +input[type="search"].suffix::-webkit-search-cancel-button { + @apply pr-3.25em; +} + +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; + margin: 1em; + height: 1em; + width: 1em; + border-radius: 50em; + background: url(https://pro.fontawesome.com/releases/v5.10.0/svgs/solid/times-circle.svg) + no-repeat 50% 50%; + background-size: contain; + opacity: 0; + pointer-events: none; +} + +input[type="search"]:focus::-webkit-search-cancel-button { + opacity: 0.3; + pointer-events: all; +} + +input[type="search"].dark::-webkit-search-cancel-button { + filter: invert(1); +} diff --git a/packages/frontend-shared/src/styles/prism.scss b/packages/frontend-shared/src/styles/prism.scss new file mode 100644 index 0000000000..264cbe6405 --- /dev/null +++ b/packages/frontend-shared/src/styles/prism.scss @@ -0,0 +1,76 @@ +code[class*="language-"], +pre[class*="language-"] { + @apply text-gray-500; + text-shadow: $white 0px 1px; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + @apply text-red-500; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + @apply text-jade-500; +} + +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.regex, +.token.important, +.token.variable { + @apply text-orange-500; + @apply bg-gray-50; +} + +.token.operator, +.token.punctuation { + @apply text-gray-500; +} + +.token.atrule, +.token.attr-value, +.token.class-name { + @apply text-indigo-500; +} + +.token.keyword, +.token.function { + @apply text-purple-500; +} + +.token.comment { + @apply text-gray-500; +} + +.line-numbers .line-numbers-rows { + @apply border-r-0; +} + +.line-numbers-rows > span:before { + @apply text-gray-200; +} + +.line-highlight { + @apply bg-gray-100; + + &:before { + @apply hidden; + } +} + +.test-error-code-frame pre[data-line] { + @apply pl-2; + @apply relative; +} diff --git a/packages/frontend-shared/src/styles/shared.scss b/packages/frontend-shared/src/styles/shared.scss new file mode 100644 index 0000000000..ed52fa91bf --- /dev/null +++ b/packages/frontend-shared/src/styles/shared.scss @@ -0,0 +1,318 @@ +@use './normalize.scss'; + +/* Define the "system" font family */ +@font-face { + font-family: system; + font-style: normal; + font-weight: 300; + src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), + local(".LucidaGrandeUI"), local("Ubuntu Light"), local("Segoe UI Light"), + local("Roboto-Light"), local("DroidSans"), local("Tahoma"); +} + +/* Set up Roboto for modern browsers, all weights */ +@supports (font-variation-settings: normal) { + @font-face { + font-family: 'Fira Code'; + src: url('/fonts/FiraCode-VF.woff2') format('woff2 supports variations'), + url('/fonts/FiraCode-VF.woff2') format('woff2-variations'); + font-weight: 100 1000; + font-stretch: 25% 151%; + } +} + +html, body { + @apply bg-white font-sans antialiased; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +/** + * Utilities + * ------------------------- + */ + +// Hides the scrollbar when overflow: auto. Use this sparingly -- it's not accessible! +.hide-scrollbar { + scrollbar-width: 0; // Firefox + + // Chrome + &::-webkit-scrollbar { + width: 0; + height: 0; + } +} + +// Dark scrollbars, anything with dark: +.force-dark { + color-scheme: dark; +} + +// Light scrollbars, anything with light: +.force-light { + color-scheme: light; +} + +/** + * Common theming + * ------------------------- + */ + +::selection { + @apply bg-gray-200 bg-opacity-30; +} + +/** + * Global Resets + * ------------------------- + */ + +// Input Resets +// Taken from Tailwind CSS Forms -- a plugin for tailwind. +// We could probably add these into WindiCSS directly +// https://github.com/tailwindlabs/tailwindcss-forms +// [type="search"]::-webkit-search-cancel-button, +// [type="search"]::-webkit-search-decoration { +// -webkit-appearance: none !important; +// appearance: none !important; +// } + +[multiple], +[type=date], +[type=datetime-local], +[type=email], +[type=month], +[type=number], +[type=password], +[type=search], +[type=tel], +[type=text], +[type=time], +[type=url], +[type=week], +select, +textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + border-radius: 0; + padding-top: 0.35rem; + padding-bottom: 0.35rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + font-size: 1rem; + line-height: 1.25rem; +} + +[multiple]:focus, +[type=date]:focus, +[type=datetime-local]:focus, +[type=email]:focus, +[type=month]:focus, +[type=number]:focus, +[type=password]:focus, +[type=search]:focus, +[type=tel]:focus, +[type=text]:focus, +[type=time]:focus, +[type=url]:focus, +[type=week]:focus, +select:focus, +textarea:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty, ); + /*!*/ + /*!*/ + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + border-color: #2563eb; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + color: #6b7280; + opacity: 1; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #6b7280; + opacity: 1; +} + +input::placeholder, +textarea::placeholder { + color: #6b7280; + opacity: 1; +} + +::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +::-webkit-date-and-time-value { + min-height: 1.5em; +} + +select { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right .5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + color-adjust: exact; +} + +[multiple] { + background-image: initial; + background-position: initial; + background-repeat: unset; + background-size: initial; + padding-right: .75rem; + -webkit-print-color-adjust: unset; + color-adjust: unset; +} + +[type=checkbox], +[type=radio] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + -webkit-print-color-adjust: exact; + color-adjust: exact; + display: inline-block; + vertical-align: middle; + background-origin: border-box; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #2563eb; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; +} + +[type=checkbox] { + border-radius: 0; +} + +[type=radio] { + border-radius: 100%; +} + +[type=checkbox]:focus, +[type=radio]:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty); + --tw-ring-offset-width: 2px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); +} + +[type=checkbox]:checked, +[type=radio]:checked { + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +[type=checkbox]:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); +} + +[type=radio]:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); +} + +[type=checkbox]:checked:focus, +[type=checkbox]:checked:hover, +[type=radio]:checked:focus, +[type=radio]:checked:hover { + border-color: transparent; + background-color: currentColor; +} + +[type=checkbox]:indeterminate { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +[type=checkbox]:indeterminate:focus, +[type=checkbox]:indeterminate:hover { + border-color: transparent; + background-color: currentColor; +} + +[type=file] { + background: unset; + border-color: inherit; + border-width: 0; + border-radius: 0; + padding: 0; + font-size: unset; + line-height: inherit; +} + +[type=file]:focus { + outline: 1px auto -webkit-focus-ring-color; +} + + +input[type="search"].dark { + background: #222; + color: #fff; +} + +input[type="search"].light { + background: #fff; + color: #222; +} +input[type="search"].suffix::-webkit-search-cancel-button { + @apply pr-3.25em; +} + +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; + margin: 1em; + height: 1em; + width: 1em; + border-radius: 50em; + background: url(https://pro.fontawesome.com/releases/v5.10.0/svgs/solid/times-circle.svg) + no-repeat 50% 50%; + background-size: contain; + opacity: 0; + pointer-events: none; +} + +input[type="search"]:focus::-webkit-search-cancel-button { + opacity: 0.3; + pointer-events: all; +} + +input[type="search"].dark::-webkit-search-cancel-button { + filter: invert(1); +} diff --git a/packages/frontend-shared/src/utils/base64.ts b/packages/frontend-shared/src/utils/base64.ts new file mode 100644 index 0000000000..8dc6df3509 --- /dev/null +++ b/packages/frontend-shared/src/utils/base64.ts @@ -0,0 +1,39 @@ +/** + * Correctly decodes Unicode string in encoded in base64 + * Copied from driver/src/cypress/utils.ts + * + * @see https://github.com/cypress-io/cypress/issues/5435 + * @see https://github.com/cypress-io/cypress/issues/7507 + * @see https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings + * + * @example + ``` + Buffer.from(JSON.stringify({state: '๐Ÿ™‚'})).toString('base64') + // 'eyJzdGF0ZSI6IvCfmYIifQ==' + // "window.atob" does NOT work + // atob('eyJzdGF0ZSI6IvCfmYIifQ==') + // "{"state":"รฐยŸย™ย‚"}" + // but this function works + b64DecodeUnicode('eyJzdGF0ZSI6IvCfmYIifQ==') + '{"state":"๐Ÿ™‚"}' + ``` +*/ + +export function decodeBase64Unicode (str: string) { + return decodeURIComponent(atob(str).split('').map((char) => { + return `%${(`00${char.charCodeAt(0).toString(16)}`).slice(-2)}` + }).join('')) +} + +/** + * Copied from driver/src/cypress/utils.ts + * + * Correctly encodes Unicode string to base64 + * @see https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings +*/ +export function encodeBase64Unicode (str: string) { + return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => { + // @ts-ignore + return String.fromCharCode(`0x${p1}`) + })) +} diff --git a/packages/frontend-shared/src/utils/decodeBase64.ts b/packages/frontend-shared/src/utils/decodeBase64.ts new file mode 100644 index 0000000000..8dc6df3509 --- /dev/null +++ b/packages/frontend-shared/src/utils/decodeBase64.ts @@ -0,0 +1,39 @@ +/** + * Correctly decodes Unicode string in encoded in base64 + * Copied from driver/src/cypress/utils.ts + * + * @see https://github.com/cypress-io/cypress/issues/5435 + * @see https://github.com/cypress-io/cypress/issues/7507 + * @see https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings + * + * @example + ``` + Buffer.from(JSON.stringify({state: '๐Ÿ™‚'})).toString('base64') + // 'eyJzdGF0ZSI6IvCfmYIifQ==' + // "window.atob" does NOT work + // atob('eyJzdGF0ZSI6IvCfmYIifQ==') + // "{"state":"รฐยŸย™ย‚"}" + // but this function works + b64DecodeUnicode('eyJzdGF0ZSI6IvCfmYIifQ==') + '{"state":"๐Ÿ™‚"}' + ``` +*/ + +export function decodeBase64Unicode (str: string) { + return decodeURIComponent(atob(str).split('').map((char) => { + return `%${(`00${char.charCodeAt(0).toString(16)}`).slice(-2)}` + }).join('')) +} + +/** + * Copied from driver/src/cypress/utils.ts + * + * Correctly encodes Unicode string to base64 + * @see https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings +*/ +export function encodeBase64Unicode (str: string) { + return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => { + // @ts-ignore + return String.fromCharCode(`0x${p1}`) + })) +} diff --git a/packages/frontend-shared/src/utils/getUrlWithParams.ts b/packages/frontend-shared/src/utils/getUrlWithParams.ts new file mode 100644 index 0000000000..e0e46944fa --- /dev/null +++ b/packages/frontend-shared/src/utils/getUrlWithParams.ts @@ -0,0 +1,14 @@ +export type LinkWithParams = { + url: string + params: { [key: string]: string } +} + +export const getUrlWithParams = (link: LinkWithParams) => { + let result = link.url + + if (link.params) { + result += `?${new URLSearchParams(link.params).toString()}` + } + + return result +} diff --git a/packages/frontend-shared/src/utils/sortBrowsers.ts b/packages/frontend-shared/src/utils/sortBrowsers.ts new file mode 100644 index 0000000000..d7e6e2bb79 --- /dev/null +++ b/packages/frontend-shared/src/utils/sortBrowsers.ts @@ -0,0 +1,3 @@ +export default function sortBrowsers (browsers) { + return browsers.sort((a, b) => a.displayName > b.displayName ? 1 : -1) +} diff --git a/packages/frontend-shared/src/utils/spec-utils.ts b/packages/frontend-shared/src/utils/spec-utils.ts new file mode 100644 index 0000000000..6ce885919f --- /dev/null +++ b/packages/frontend-shared/src/utils/spec-utils.ts @@ -0,0 +1,155 @@ +import fuzzySort from 'fuzzysort' +import type { FoundSpec } from '@packages/types' +import { ComputedRef, Ref, ref, watch } from 'vue' +import type { UseCollapsibleTreeNode } from '../composables/useCollapsibleTree' + +const PATH_SEP = /[\/\\]/ + +export type FuzzyFoundSpec = FoundSpec & { + fileIndexes: number[] + dirIndexes: number[] +} + +export type SpecTreeNode = { + id: string + name: string + children: SpecTreeNode[] + isLeaf: boolean + parent?: SpecTreeNode + data?: T +} + +export function buildSpecTree (specs: FoundSpec[], root: SpecTreeNode = { name: '', isLeaf: false, children: [], id: '' }) { + specs.forEach((spec) => buildSpecTreeRecursive(spec.relative, root, spec)) + collapseEmptyChildren(root) + + return root +} + +export function buildSpecTreeRecursive (path: string, tree: SpecTreeNode, data?: T) { + const [firstFile, ...rest] = path.split(PATH_SEP) + const id = tree.id ? [tree.id, firstFile].join('/') : firstFile + + if (rest.length < 1) { + tree.children.push({ name: firstFile, isLeaf: true, children: [], parent: tree, data, id }) + + return tree + } + + const foundChild = tree.children.find((child) => child.name === firstFile) + + if (foundChild) { + buildSpecTreeRecursive(rest.join('/'), foundChild, data) + + return tree + } + + const newTree = buildSpecTreeRecursive(rest.join('/'), { name: firstFile, isLeaf: false, children: [], parent: tree, id, data }, data) + + tree.children.push(newTree) + + return tree +} + +function collapseEmptyChildren (node: SpecTreeNode) { + for (const child of node.children) { + collapseEmptyChildren(child) + } + if (node.isLeaf) { + return + } + + // Root name of our tree is '/'. We don't want to collapse into the root node + // so we check node.parent.parent + if (node.parent && node.parent.parent && (node.parent.children.length === 1)) { + node.parent.name = [node.parent.name, node.name].join('/') + node.parent.id = [node.parent.id, node.name].join('/') + node.parent.children = node.children + } + + return +} + +export function getDirIndexes (row: UseCollapsibleTreeNode>) { + const indexes = row.data?.dirIndexes ?? [] + + const maxIndex = row.id.length - 1 + const minIndex = maxIndex - row.name.length + 1 + + const res = indexes.filter((index) => index >= minIndex && index <= maxIndex) + + return res.map((idx) => idx - minIndex) +} + +export function fuzzySortSpecs (specs: FuzzyFoundSpec[], searchValue: string) { + const transformedSpecs = addDirectoryToSpecs(specs) + + return fuzzySort + .go(searchValue, transformedSpecs, { keys: ['baseName', 'directory'], allowTypo: false }) + .map((result) => { + const [file, dir] = result + + return { + ...result.obj, + fileIndexes: file?.indexes ?? [], + dirIndexes: dir?.indexes ?? [], + } + }) as FuzzyFoundSpec[] +} + +function addDirectoryToSpecs (specs: Partial[]) { + return specs.map((spec) => { + return { + ...spec, + directory: getDirectoryPath(spec?.relative ?? ''), + } + }) +} + +function getDirectoryPath (path: string) { + return path.slice(0, path.lastIndexOf('/') ?? path.lastIndexOf('\\')) +} + +export function makeFuzzyFoundSpec (spec: FoundSpec): FuzzyFoundSpec { + return { + ...spec, + fileIndexes: [], + dirIndexes: [], + } +} + +export type SpecsComparator> = ( + specs: Readonly, + oldSpecs: Readonly +) => boolean + +type FileLike = { + absolute: string +} + +function defaultCompareFn ( + specs: Readonly>, + oldSpecs: Readonly>, +) { + return specs.some((spec, idx) => spec.absolute !== oldSpecs[idx]?.absolute) +} + +export function useCachedSpecs ( + specs: ComputedRef>, + compareFn?: SpecsComparator, +): Ref> { + const cachedSpecs: Ref> = ref([]) + + watch(specs, (currentSpecs, prevSpecs = []) => { + const comparer = compareFn?.(currentSpecs, prevSpecs) || defaultCompareFn(currentSpecs, prevSpecs) + + const specsAreDifferent = + currentSpecs.length !== prevSpecs?.length || comparer + + if (specsAreDifferent) { + cachedSpecs.value = currentSpecs + } + }, { immediate: true }) + + return cachedSpecs +} diff --git a/packages/frontend-shared/src/utils/time.ts b/packages/frontend-shared/src/utils/time.ts new file mode 100644 index 0000000000..a4fd360e71 --- /dev/null +++ b/packages/frontend-shared/src/utils/time.ts @@ -0,0 +1,9 @@ +import enTimeAgo from 'javascript-time-ago/locale/en' +import TimeAgo from 'javascript-time-ago' + +TimeAgo.addDefaultLocale(enTimeAgo) +const timeAgo = new TimeAgo('en-US') + +export function getTimeAgo (iso8601: string) { + return timeAgo.format(new Date(iso8601)) +} diff --git a/packages/frontend-shared/src/warning/Warning.cy.tsx b/packages/frontend-shared/src/warning/Warning.cy.tsx new file mode 100644 index 0000000000..8efd0d2f96 --- /dev/null +++ b/packages/frontend-shared/src/warning/Warning.cy.tsx @@ -0,0 +1,49 @@ +import { defaultMessages } from '@cy/i18n' +import Warning from './Warning.vue' +import faker from 'faker' +import { ref } from 'vue' + +const title = faker.hacker.noun() +const message = ` +# Hello! +> This is a **markdown formatted** message! + +We're going to print out some \`console.log('cool code')\` and see how well it formats inside of our warning. +` + +describe('', () => { + it('renders with title and message', () => { + cy.mount(() => (
)) + + cy.contains(title) + cy.get('[data-testid=warning]') + .should('contain.text', 'Hello!') + .and('contain.text', 'This is a markdown formatted message!') + .and('contain.text', `We're going to print out some console.log('cool code') and see how well it formats inside of our warning.`) + }) + + it('calls dismiss when X is clicked', () => { + const show = ref(true) + const onUpdate = cy.spy() + const methods = { + 'onUpdate:modelValue': (value) => { + show.value = value + onUpdate() + }, + } + + cy.mount(() => (
)) + + cy.get(`[aria-label=${defaultMessages.components.alert.dismissAriaLabel}`).first().click() + cy.wrap(onUpdate).should('be.called') + }) +}) diff --git a/packages/frontend-shared/src/warning/Warning.vue b/packages/frontend-shared/src/warning/Warning.vue new file mode 100644 index 0000000000..9523e1ccce --- /dev/null +++ b/packages/frontend-shared/src/warning/Warning.vue @@ -0,0 +1,69 @@ + + + diff --git a/packages/frontend-shared/tsconfig.json b/packages/frontend-shared/tsconfig.json new file mode 100644 index 0000000000..1538e60de8 --- /dev/null +++ b/packages/frontend-shared/tsconfig.json @@ -0,0 +1,74 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "ES2018", + "module": "esnext", + "lib": ["dom", "ESNext"], + /* + * Allow javascript files to be compiled. + * Override this in modules that need JS + */ + "noEmit": true, + "jsx": "preserve", + "preserveWatchOutput": true, + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + /* Generates corresponding '.d.ts' file. */ + // "declaration": true, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + /* Generates corresponding '.map' file. */ + "sourceMap": true, + /* Import emit helpers from 'tslib'. */ + "importHelpers": true, + "strictNullChecks": true, + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + // "traceResolution": true, + "strict": true, + "noImplicitAny": false, + "noImplicitThis": false, + "forceConsistentCasingInFileNames": true, + /** + * Skip type checking of all declaration files (*.d.ts). + * TODO: Look into changing this in the future + */ + /* Additional Checks */ + "skipLibCheck": true, + /* Report errors on unused locals. */ + // "noEmit": true, + "noUnusedLocals": false, + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + /* Report error when not all code paths in function return a value. */ + "noImplicitReturns": true, + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": ["../driver/src"], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [] /* List of folders to include type definitions from. */ + + /* Type declaration files to be included in compilation. */ + "paths": { + "@cy/i18n": ["../frontend-shared/src/locales/i18n"], + "@cy/components/*": ["../frontend-shared/src/components/*"] + }, + "types": [ + "chrome", + "./vue-shims", + "./vite-env", + "@intlify/vite-plugin-vue-i18n/client", + "@testing-library/cypress", + "cypress-real-events", + "cypress" + ], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "noErrorTruncation": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "importsNotUsedAsValues": "error", + "useUnknownInCatchVariables": false + } +} diff --git a/packages/frontend-shared/vite-env.d.ts b/packages/frontend-shared/vite-env.d.ts new file mode 100644 index 0000000000..8cee151713 --- /dev/null +++ b/packages/frontend-shared/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/packages/frontend-shared/vite.config.ts b/packages/frontend-shared/vite.config.ts new file mode 100644 index 0000000000..8a90b2f8b0 --- /dev/null +++ b/packages/frontend-shared/vite.config.ts @@ -0,0 +1,135 @@ +import path from 'path' +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import WindiCSS from 'vite-plugin-windicss' +import VueI18n from '@intlify/vite-plugin-vue-i18n' +import VueSvgLoader from 'vite-svg-loader' +import Components from 'unplugin-vue-components/vite' +import Icons from 'unplugin-icons/vite' +import IconsResolver from 'unplugin-icons/resolver' +import { FileSystemIconLoader } from 'unplugin-icons/loaders' + +import PkgConfig from 'vite-plugin-package-config' + +// eslint-disable-next-line no-duplicate-imports +import type { UserConfig } from 'vite' +import type { ArgumentsType } from '@antfu/utils' + +type PluginOptions = { + plugins?: any[] + + // These types aren't publicly exported + vueI18nOptions?: ArgumentsType[0] + iconsOptions?: ArgumentsType[0] + componentsOptions?: ArgumentsType[0] +} + +const base = './' + +const alias = { + '@cy/components': path.resolve(__dirname, './src/components'), + '@cy/gql-components': path.resolve(__dirname, './src/gql-components'), + + // import { defaultMessages, useI18n } from '@cy/i18n' + '@cy/i18n': path.resolve(__dirname, './src/locales/i18n'), +} + +const makePlugins = (plugins) => { + return ([ + vue(), + vueJsx(), // Used mostly for testing in *.(t|j)sx files. + VueI18n({ + include: path.resolve(__dirname, './src/locales/**'), + ...plugins.vueI18nOptions, + }), + Icons({ + // 1em. Default, without this options is 1.2em. + // If you notice that your icons are bigger than they should be, this + // is probably why. + scale: 1, + customCollections: { + // ~icons/cy/book_x16 + cy: FileSystemIconLoader(path.resolve(__dirname, './src/assets/icons')), + ...plugins.iconsOptions?.customCollections, + }, + ...plugins.iconsOptions, + }), + Components({ + resolvers: IconsResolver({ + // + customCollections: ['cy'], + }), + ...plugins?.componentsOptions, + }), + WindiCSS(), + VueSvgLoader(), + + // package.json is modified and auto-updated when new cjs dependencies + // are added + PkgConfig(), + // OptimizationPersist(), + // For new plugins only! Merge options for shared plugins via PluginOptions. + ...(plugins?.plugins || []), + ]) +} + +export const makeConfig = (config: Partial = {}, plugins: PluginOptions = {}): UserConfig => { + // Don't overwrite plugins + delete config.plugins + + return { + base, + publicDir: path.resolve(__dirname, './src/public'), + + // Production-only build options + build: { + minify: false, + }, + + css: { + preprocessorOptions: { + scss: { + additionalData: `@use "file:///${path.resolve(__dirname, '../reporter/src/lib/variables.scss').replaceAll('\\', '/')}" as *;\n`, + }, + }, + }, + + resolve: { + alias, + dedupe: [ + 'vue', + '@vue/compiler-core', + '@vue/compiler-dom', + '@vue/compiler-sfc', + '@vueuse/core', + '@urql/core', + '@urql/devtools', + '@urql/exchange-execute', + '@urql/exchange-graphcache', + '@urql/vue', + ], + }, + server: { + fs: { + // Since we're in a monorepo, we're going to serve packages from + // npm/vue/dist/* and other local places. This enables us to do that. + // https://vitejs.dev/config/#server-fs-strict + strict: false, + }, + }, + + // You cannot add or remove arbitrary options from shared plugins. + // Please use the PluginsOverride option for this. + plugins: makePlugins(plugins), + define: { + 'process.env': { + CYPRESS_INTERNAL_ENV: 'development', + }, + 'setImmediate': {}, + }, + ...config, + } +} + +export default defineConfig(makeConfig()) diff --git a/packages/frontend-shared/vue-shims.d.ts b/packages/frontend-shared/vue-shims.d.ts new file mode 100644 index 0000000000..fd758ac762 --- /dev/null +++ b/packages/frontend-shared/vue-shims.d.ts @@ -0,0 +1,32 @@ +declare module 'virtual:*' { + import { Component } from 'vue' + const src: Component + export default src +} + +declare module 'virtual:icons/*' { + // eslint-disable-next-line no-duplicate-imports + import { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} +declare module '~icons/*' { + // eslint-disable-next-line no-duplicate-imports + import { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} + +declare module '~icons/cy/*' { + // eslint-disable-next-line no-duplicate-imports + import { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} + +declare module '~icons/mdi/*' { + // eslint-disable-next-line no-duplicate-imports + import { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} diff --git a/packages/frontend-shared/windi.config.ts b/packages/frontend-shared/windi.config.ts new file mode 100644 index 0000000000..872292996f --- /dev/null +++ b/packages/frontend-shared/windi.config.ts @@ -0,0 +1,54 @@ +import { defineConfig } from 'windicss/helpers' +import InteractionVariants from '@windicss/plugin-interaction-variants' +import { IconDuotoneColorsPlugin } from './.windicss/icon-color-plugins' +import { safelist } from './.windicss/safelist' +import { colors } from './.windicss/colors' +import { shortcuts } from './.windicss/shortcuts' +import path from 'path' +import type { FullConfig } from 'windicss/types/interfaces' + +export const defaultConfig: FullConfig = { + // This adds !important to all utility classes. + // https://csswizardry.com/2016/05/the-importance-of-important/ + important: true, + theme: { + extend: { + borderRadius: { + DEFAULT: '4px', + md: '4px' }, + fontFamily: { + mono: '"Fira Code", monospace', + }, + colors, + cursor: { + 'ew-resize': 'ew-resize', + }, + }, + }, + safelist, + variants: { + // What's hocus? + // Hocus is a portmanteau of hover + focus. This is useful because + // many of our styles are the same for both hover and focus. + backgroundColor: ['group-focus-within', 'group-focus-visible', 'group-active', 'group-visited', 'group-disabled', 'hocus', 'group-hocus', 'can-hover', 'no-hover'], + }, + plugins: [ + IconDuotoneColorsPlugin, + InteractionVariants, + require('windicss/plugin/filters'), + ], + shortcuts, + extract: { + // accepts globs and file paths relative to project root + include: [ + 'index.html', + '**/*.{vue,html,tsx}', + path.resolve(__dirname, '../frontend-shared/**/*.{vue,html,tsx,svg}'), + path.resolve(__dirname, '../app/**/*.{vue,html,tsx,svg}'), + path.resolve(__dirname, '../launchpad/**/*.{vue,html,tsx,svg}'), + ], + exclude: ['node_modules/**/*', '.git/**/*'], + }, +} + +export default defineConfig(defaultConfig) diff --git a/packages/graphql/.eslintrc.json b/packages/graphql/.eslintrc.json new file mode 100644 index 0000000000..0eda50e708 --- /dev/null +++ b/packages/graphql/.eslintrc.json @@ -0,0 +1,62 @@ +{ + "extends": [ + "plugin:@cypress/dev/general", + "plugin:@cypress/dev/tests" + ], + "parser": "@typescript-eslint/parser", + "env": { + "cypress/globals": true + }, + "plugins": [ + "cypress" + ], + "overrides": [ + { + "files": [ + "./src/entities/**/*.ts" + ], + "rules": { + "no-useless-constructor": "off", + "@typescript-eslint/explicit-function-return-type": [ + "error" + ], + "no-restricted-imports": [ + "error", + "assert", + "buffer", + "child_process", + "cluster", + "crypto", + "dgram", + "dns", + "domain", + "events", + "freelist", + "fs", + "http", + "https", + "module", + "net", + "os", + "path", + "punycode", + "querystring", + "readline", + "repl", + "smalloc", + "stream", + "string_decoder", + "sys", + "timers", + "tls", + "tracing", + "tty", + "url", + "util", + "vm", + "zlib" + ] + } + } + ] +} diff --git a/packages/graphql/.gitignore b/packages/graphql/.gitignore new file mode 100644 index 0000000000..6724ce3596 --- /dev/null +++ b/packages/graphql/.gitignore @@ -0,0 +1 @@ +src/**/*.js \ No newline at end of file diff --git a/packages/graphql/README.md b/packages/graphql/README.md new file mode 100644 index 0000000000..2b17a77708 --- /dev/null +++ b/packages/graphql/README.md @@ -0,0 +1,29 @@ +# GraphQL + +The GraphQL layer that `@packages/launchpad` and `@packages/runner` use to interact with `@packages/server`. + +With the goal of type safety, several tools and abstractions are used. The technologies are: + +- [nexus-graphql](https://nexusjs.org/) library for generating GraphQL schema using TypeScript objects +- [graphql-code-generator](https://www.graphql-code-generator.com/) generate TypeScript types from `gql` queries (for front-end consuming the API) + +[This tutorial](https://github.com/lmiller1990/vue-3-urql-example) demonstrates how to build a type-safe GraphQL app using the above technologies. It's a good place to start, to learn how and why each tool is used. + +## Development + +You will generally develop this in parallel with a front-end, in this case `@packages/launchpad`. Run `yarn dev` in `@packages/launchpad` and it will start up the GraphQL server. This also re-generates the `graphql.schema` file based on the declarations inside of [entities](https://github.com/cypress-io/cypress/blob/develop/packages/graphql/src/entities). + +Visit `http://localhost:52200/graphql` for the GraphiQL interface. + +![graphql](./gql.png) + +You can also develop in a test-driven manner using the tests. + +- `yarn test-unit` for the unit tests +- `yarn test-integration` for the integration tests + +## Debugging + +Logs available at `cypress-verbose:graphql:*` namespaces `{fields,operation}` + + diff --git a/packages/graphql/gql.png b/packages/graphql/gql.png new file mode 100644 index 0000000000..4000f6f813 Binary files /dev/null and b/packages/graphql/gql.png differ diff --git a/packages/graphql/index.js b/packages/graphql/index.js new file mode 100644 index 0000000000..643cb42256 --- /dev/null +++ b/packages/graphql/index.js @@ -0,0 +1,5 @@ +if (process.env.CYPRESS_INTERNAL_ENV !== 'production') { + require('@packages/ts/register') +} + +module.exports = require('./src') diff --git a/packages/graphql/package.json b/packages/graphql/package.json new file mode 100644 index 0000000000..c4cabfd676 --- /dev/null +++ b/packages/graphql/package.json @@ -0,0 +1,50 @@ +{ + "name": "@packages/graphql", + "version": "0.0.0-development", + "private": true, + "main": "index.js", + "browser": "src/index.ts", + "scripts": { + "build-prod": "tsc || echo 'built, with errors'", + "check-ts": "tsc --noEmit && yarn -s tslint", + "clean-deps": "rimraf node_modules", + "clean": "rimraf './{src,test}/**/*.js'", + "tslint": "tslint --config ../ts/tslint.json --project .", + "postinstall": "echo '@packages/graphql needs: yarn build'", + "test-unit": "mocha -r @packages/ts/register test/unit/**/*.spec.ts --config ./test/.mocharc.js --exit", + "test-integration": "mocha -r @packages/ts/register test/integration/**/*.spec.ts --config ./test/.mocharc.js --exit" + }, + "dependencies": { + "@graphql-tools/batch-delegate": "8.1.0", + "@graphql-tools/delegate": "8.2.1", + "@graphql-tools/utils": "8.2.3", + "@graphql-tools/wrap": "8.1.1", + "dedent": "^0.7.0", + "express": "4.17.1", + "express-graphql": "^0.12.0", + "getenv": "1.0.0", + "graphql": "^15.5.1", + "graphql-scalars": "^1.10.0", + "graphql-ws": "^5.5.5", + "nexus": "^1.2.0-next.15", + "server-destroy": "^1.0.1", + "ws": "^8.5.0" + }, + "devDependencies": { + "@packages/data-context": "0.0.0-development", + "@packages/root": "0.0.0-development", + "@packages/types": "0.0.0-development", + "@types/dedent": "^0.7.0", + "@types/server-destroy": "^1.0.1", + "chai": "^4.2.0", + "mocha": "^8.1.3", + "rimraf": "3.0.2", + "snap-shot-it": "7.9.3", + "tslint": "^6.1.3" + }, + "files": [ + "src", + "schemas" + ], + "types": "src/index.ts" +} diff --git a/packages/graphql/schemas/cloud.graphql b/packages/graphql/schemas/cloud.graphql new file mode 100644 index 0000000000..5bba7a93c4 --- /dev/null +++ b/packages/graphql/schemas/cloud.graphql @@ -0,0 +1,491 @@ +### This file was generated by Nexus Schema +### Do not make changes to this file directly + +""" +A CloudOrganization represents an Organization stored in the Cypress Cloud +""" +type CloudOrganization implements Node { + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! + + """ + Name of the organization + """ + name: String + + """ + A connection for cloud projects associated with this organization + """ + projects( + """ + Returns the elements in the list that come after the specified cursor + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor + """ + before: String + + """ + Returns the first n elements from the list. + """ + first: Int + + """ + Returns the last n elements from the list. + """ + last: Int + ): CloudProjectConnection +} + +type CloudOrganizationConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudOrganizationEdge!]! + + """ + Flattened list of CloudOrganization type + """ + nodes: [CloudOrganization!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudOrganizationEdge { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor + """ + cursor: String! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Node + """ + node: CloudOrganization! +} + +""" +A CloudProject represents a Project stored in the Cypress Cloud +""" +type CloudProject implements Node { + """ + A link to the settings page of the project in the dashboard + """ + cloudProjectSettingsUrl: String! + + """ + A link to the project in the dashboard + """ + cloudProjectUrl: String! + + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! + + """ + The latest run for a given spec + """ + latestRun: CloudRun + + """ + Given name of the project + """ + name: String! + + """ + The organization the project is a member of + """ + organization: CloudOrganization + + """ + Record keys for the service + """ + recordKeys: [CloudRecordKey!] + + """ + A connection field type + """ + runs( + """ + Returns the elements in the list that come after the specified cursor + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor + """ + before: String + cypressVersion: String + + """ + Returns the first n elements from the list. + """ + first: Int + + """ + Returns the last n elements from the list. + """ + last: Int + status: CloudRunStatus + ): CloudRunConnection + + """ + Unique identifier for a Project + """ + slug: String! +} + +type CloudProjectConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudProjectEdge!]! + + """ + Flattened list of CloudProject type + """ + nodes: [CloudProject!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudProjectEdge { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor + """ + cursor: String! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Node + """ + node: CloudProject! +} + +""" +Unable to find cloud project +""" +type CloudProjectNotFound { + """ + an error message + """ + message: String! +} + +union CloudProjectResult = + CloudProject + | CloudProjectNotFound + | CloudProjectUnauthorized + +""" +Unauthorized access +""" +type CloudProjectUnauthorized { + """ + does the user have a requested access pending + """ + hasRequestedAccess: Boolean + + """ + an error message + """ + message: String! +} + +type CloudRecordKey implements Node { + createdAt: DateTime + + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! + + """ + The Record Key + """ + key: String + lastUsedAt: DateTime +} + +""" +A Recorded run of the Test Runner, typically to the cloud +""" +type CloudRun implements Node { + commitInfo: CloudRunCommitInfo + createdAt: DateTime + + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! + status: CloudRunStatus + + """ + Total duration of the run in milliseconds, accounting for any parallelization + """ + totalDuration: Int + + """ + This is the number of failed tests across all groups in the run + """ + totalFailed: Int + + """ + This is the number of passed tests across all groups in the run + """ + totalPassed: Int + + """ + This is the number of pending tests across all groups in the run + """ + totalPending: Int + + """ + This is the number of running tests across all groups in the run + """ + totalRunning: Int + + """ + This is the number of skipped tests across all groups in the run + """ + totalSkipped: Int + + """ + This is the number of tests across all groups in the run + """ + totalTests: Int + + """ + A link to the run page + """ + url: String +} + +type CloudRunCommitInfo { + authorAvatar: String + authorEmail: String + authorName: String + branch: String + branchUrl: String + message( + """ + Number of characters to truncate the commit message to + """ + truncate: Int + ): String + sha: String + summary: String + url: String +} + +type CloudRunConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudRunEdge!]! + + """ + Flattened list of CloudRun type + """ + nodes: [CloudRun!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudRunEdge { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor + """ + cursor: String! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Node + """ + node: CloudRun! +} + +""" +Possible check status of the test run +""" +enum CloudRunStatus { + CANCELLED + ERRORED + FAILED + NOTESTS + OVERLIMIT + PASSED + RUNNING + TIMEDOUT +} + +""" +A CloudUser represents an User stored in the Cypress Cloud +""" +type CloudUser implements Node { + """ + Url to manage cloud organizations for this user + """ + cloudOrganizationsUrl: String + + """ + Url to the profile of the current user on the dashboard + """ + cloudProfileUrl: String + + """ + Url to create a cloud organization for this user + """ + createCloudOrganizationUrl: String + email: String + + """ + The display name of the user, if we have one + """ + fullName: String + + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! + + """ + A connection field type + """ + organizations( + """ + Returns the elements in the list that come after the specified cursor + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor + """ + before: String + + """ + Returns the first n elements from the list. + """ + first: Int + + """ + Returns the last n elements from the list. + """ + last: Int + ): CloudOrganizationConnection + + """ + Whether this user is the currently authenticated user + """ + userIsViewer: Boolean! +} + +""" +A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar Date + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +type Mutation { + """ + Create a project in the dashboard and return its object + """ + cloudProjectCreate( + ciProviders: [String!] + name: String! + orgId: ID! + public: Boolean! + ): CloudProject + + """ + Request access to an organization from a projectId + """ + cloudProjectRequestAccess(projectSlug: String!): CloudProjectResult + + """ + Adding as a test + """ + test: Boolean +} + +""" +Implements the Relay Node spec +""" +interface Node { + """ + Globally unique identifier representing a concrete GraphQL ObjectType + """ + id: ID! +} + +""" +PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo +""" +type PageInfo { + """ + The cursor corresponding to the last nodes in edges. Null if the connection is empty. + """ + endCursor: String + + """ + Used to indicate whether more edges exist following the set defined by the clients arguments. + """ + hasNextPage: Boolean! + + """ + Used to indicate whether more edges exist prior to the set defined by the clients arguments. + """ + hasPreviousPage: Boolean! + + """ + The cursor corresponding to the first nodes in edges. Null if the connection is empty. + """ + startCursor: String +} + +type Query { + """ + Returns an object conforming to the Relay spec + """ + cloudNode( + """ + An ID for a Node conforming to the Relay spec + """ + id: ID! + ): Node + + """ + Lookup an individual project by the slug + """ + cloudProjectBySlug(slug: String!): CloudProjectResult + + """ + Lookup a list of projects by their slug + """ + cloudProjectsBySlugs( + """ + A list of Project slugs + """ + slugs: [String!]! + ): [CloudProjectResult] + + """ + A user within the Cypress Cloud + """ + cloudViewer: CloudUser +} diff --git a/packages/graphql/schemas/schema.graphql b/packages/graphql/schemas/schema.graphql new file mode 100644 index 0000000000..38e36167ae --- /dev/null +++ b/packages/graphql/schemas/schema.graphql @@ -0,0 +1,1454 @@ +### This file was generated by Nexus Schema +### Do not make changes to this file directly + + +"""Represents state of auth based on most recent message from login flow""" +type AuthState { + """Whether the browser was successfully opened for login""" + browserOpened: Boolean! + + """Message for the auth state""" + message: String + + """Name of auth state, e.g. AUTH_BROWSER_LAUNCHED""" + name: AuthStateNameEnum +} + +enum AuthStateNameEnum { + AUTH_BROWSER_LAUNCHED + AUTH_COULD_NOT_LAUNCH_BROWSER + AUTH_ERROR_DURING_LOGIN +} + +"""Container representing a browser""" +type Browser implements Node { + channel: String! + disabled: Boolean! + displayName: String! + family: BrowserFamily! + + """Relay style Node ID field for the Browser field""" + id: ID! + isFocusSupported: Boolean! + isSelected: Boolean! + isVersionSupported: Boolean! + majorVersion: String + name: String! + path: String! + version: String! + warning: String +} + +enum BrowserFamily { + chromium + firefox +} + +enum BrowserStatus { + closed + open + opening +} + +""" +When we don't have an immediate response for the cloudViewer request, we'll use this as a fallback to +render the avatar in the header bar / signal authenticated state immediately +""" +type CachedUser implements Node { + """Email address of the cached user""" + email: String + + """Name of the cached user""" + fullName: String + + """Relay style Node ID field for the CachedUser field""" + id: ID! +} + +""" +A CloudOrganization represents an Organization stored in the Cypress Cloud +""" +type CloudOrganization implements Node { + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! + + """Name of the organization""" + name: String + + """A connection for cloud projects associated with this organization""" + projects( + """Returns the elements in the list that come after the specified cursor""" + after: String + + """Returns the elements in the list that come before the specified cursor""" + before: String + + """Returns the first n elements from the list.""" + first: Int + + """Returns the last n elements from the list.""" + last: Int + ): CloudProjectConnection +} + +type CloudOrganizationConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudOrganizationEdge!]! + + """Flattened list of CloudOrganization type""" + nodes: [CloudOrganization!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudOrganizationEdge { + """https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor""" + cursor: String! + + """https://facebook.github.io/relay/graphql/connections.htm#sec-Node""" + node: CloudOrganization! +} + +"""A CloudProject represents a Project stored in the Cypress Cloud""" +type CloudProject implements Node { + """A link to the settings page of the project in the dashboard""" + cloudProjectSettingsUrl: String! + + """A link to the project in the dashboard""" + cloudProjectUrl: String! + + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! + + """The latest run for a given spec""" + latestRun: CloudRun + + """Given name of the project""" + name: String! + + """The organization the project is a member of""" + organization: CloudOrganization + + """Record keys for the service""" + recordKeys: [CloudRecordKey!] + + """A connection field type""" + runs( + """Returns the elements in the list that come after the specified cursor""" + after: String + + """Returns the elements in the list that come before the specified cursor""" + before: String + cypressVersion: String + + """Returns the first n elements from the list.""" + first: Int + + """Returns the last n elements from the list.""" + last: Int + status: CloudRunStatus + ): CloudRunConnection + + """Unique identifier for a Project""" + slug: String! +} + +type CloudProjectConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudProjectEdge!]! + + """Flattened list of CloudProject type""" + nodes: [CloudProject!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudProjectEdge { + """https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor""" + cursor: String! + + """https://facebook.github.io/relay/graphql/connections.htm#sec-Node""" + node: CloudProject! +} + +"""Unable to find cloud project""" +type CloudProjectNotFound { + """an error message""" + message: String! +} + +union CloudProjectResult = CloudProject | CloudProjectNotFound | CloudProjectUnauthorized + +"""Unauthorized access""" +type CloudProjectUnauthorized { + """does the user have a requested access pending""" + hasRequestedAccess: Boolean + + """an error message""" + message: String! +} + +type CloudRecordKey implements Node { + createdAt: DateTime + + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! + + """The Record Key""" + key: String + lastUsedAt: DateTime +} + +"""A Recorded run of the Test Runner, typically to the cloud""" +type CloudRun implements Node { + commitInfo: CloudRunCommitInfo + createdAt: DateTime + + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! + status: CloudRunStatus + + """ + Total duration of the run in milliseconds, accounting for any parallelization + """ + totalDuration: Int + + """This is the number of failed tests across all groups in the run""" + totalFailed: Int + + """This is the number of passed tests across all groups in the run""" + totalPassed: Int + + """This is the number of pending tests across all groups in the run""" + totalPending: Int + + """This is the number of running tests across all groups in the run""" + totalRunning: Int + + """This is the number of skipped tests across all groups in the run""" + totalSkipped: Int + + """This is the number of tests across all groups in the run""" + totalTests: Int + + """A link to the run page""" + url: String +} + +type CloudRunCommitInfo { + authorAvatar: String + authorEmail: String + authorName: String + branch: String + branchUrl: String + message( + """Number of characters to truncate the commit message to""" + truncate: Int + ): String + sha: String + summary: String + url: String +} + +type CloudRunConnection { + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types + """ + edges: [CloudRunEdge!]! + + """Flattened list of CloudRun type""" + nodes: [CloudRun!]! + + """ + https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo + """ + pageInfo: PageInfo! +} + +type CloudRunEdge { + """https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor""" + cursor: String! + + """https://facebook.github.io/relay/graphql/connections.htm#sec-Node""" + node: CloudRun! +} + +"""Possible check status of the test run""" +enum CloudRunStatus { + CANCELLED + ERRORED + FAILED + NOTESTS + OVERLIMIT + PASSED + RUNNING + TIMEDOUT +} + +"""A CloudUser represents an User stored in the Cypress Cloud""" +type CloudUser implements Node { + """Url to manage cloud organizations for this user""" + cloudOrganizationsUrl: String + + """Url to the profile of the current user on the dashboard""" + cloudProfileUrl: String + + """Url to create a cloud organization for this user""" + createCloudOrganizationUrl: String + email: String + + """The display name of the user, if we have one""" + fullName: String + + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! + + """A connection field type""" + organizations( + """Returns the elements in the list that come after the specified cursor""" + after: String + + """Returns the elements in the list that come before the specified cursor""" + before: String + + """Returns the first n elements from the list.""" + first: Int + + """Returns the last n elements from the list.""" + last: Int + ): CloudOrganizationConnection + + """Whether this user is the currently authenticated user""" + userIsViewer: Boolean! +} + +""" +A code frame to display for a file, used when displaying code related to errors +""" +type CodeFrame { + """Source of the code frame to display""" + codeBlock: String + + """The column of the error to display""" + column: Int + file: FileParts! + + """The line number of the code snippet to display""" + line: Int +} + +"""Glob patterns for detecting files for code gen.""" +type CodeGenGlobs implements Node { + component: String! + + """Relay style Node ID field for the CodeGenGlobs field""" + id: ID! +} + +enum CodeGenType { + component + e2e + scaffoldIntegration +} + +enum CodeLanguageEnum { + js + ts +} + +""" +The currently opened Cypress project, represented by a cypress.config.{ts|js} file +""" +type CurrentProject implements Node & ProjectLike { + """The currently selected browser for the project""" + activeBrowser: Browser + + """The current branch of the project""" + branch: String + + """If the browser is open or not""" + browserStatus: BrowserStatus! + + """Browsers found that are compatible with Cypress""" + browsers: [Browser!] + + """The remote associated project from Cypress Dashboard""" + cloudProject: CloudProjectResult + + """List of all code generation candidates stories""" + codeGenCandidates(glob: String!): [FileParts] + codeGenGlobs: CodeGenGlobs! + + """Project configuration""" + config: JSON! + + """Config File, specified by the CLI or """ + configFile: String + + """Config File Absolute Path""" + configFileAbsolutePath: String + + """The mode the interactive runner was launched in""" + currentTestingType: TestingTypeEnum + + """Default spec file name for spec creation""" + defaultSpecFileName: String + + """File extension to use based on if the project has typescript or not""" + fileExtensionToUse: FileExtensionEnum + + """Whether the project has Typescript""" + hasTypescript: Boolean + + """Whether the project has a valid config file""" + hasValidConfigFile: Boolean + + """Relay style Node ID field for the CurrentProject field""" + id: ID! + + """Whether the user configured this project to use Component Testing""" + isCTConfigured: Boolean + + """True if the project is using the default spec pattern""" + isDefaultSpecPattern: Boolean! + + """Whether the user configured this project to use e2e Testing""" + isE2EConfigured: Boolean + + """Whether we are currently loading the configFile""" + isLoadingConfigFile: Boolean + + """Whether we are currently loading the setupNodeEvents""" + isLoadingNodeEvents: Boolean + + """Whether the project needs to be migrated before proceeding""" + needsLegacyConfigMigration: Boolean + packageManager: PackageManagerEnum! + + """Cached preferences for this project""" + preferences: ProjectPreferences + + """Used to associate project with Cypress dashboard""" + projectId: String + + """Absolute path to the project on the filesystem""" + projectRoot: String! + + """Project saved state""" + savedState: JSON + + """A list of specs for the currently open testing type of a project""" + specs: [Spec!]! + title: String! +} + +""" +A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar Date + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +enum DevRelaunchAction { + dismiss + trigger +} + +"""State associated/helpful for local development of Cypress""" +type DevState { + """ + When we have edited server related files, we may want to relaunch the client. + """ + needsRelaunch: Boolean + + """For debugging, the current application state""" + state: JSON +} + +"""Represents an editor on the local machine""" +type Editor { + """Binary that opens the editor""" + binary: String + id: String! + + """name of editor""" + name: String! +} + +enum ErrorTypeEnum { + AUTOMATION_SERVER_DISCONNECTED + BAD_POLICY_WARNING + BAD_POLICY_WARNING_TOOLTIP + BROWSER_NOT_FOUND_BY_NAME + BROWSER_NOT_FOUND_BY_PATH + BUNDLE_ERROR + CANNOT_CONNECT_BASE_URL + CANNOT_CONNECT_BASE_URL_RETRYING + CANNOT_CONNECT_BASE_URL_WARNING + CANNOT_CREATE_PROJECT_TOKEN + CANNOT_FETCH_PROJECT_TOKEN + CANNOT_RECORD_NO_PROJECT_ID + CANNOT_REMOVE_OLD_BROWSER_PROFILES + CANNOT_TRASH_ASSETS + CDP_COULD_NOT_CONNECT + CDP_COULD_NOT_RECONNECT + CDP_RETRYING_CONNECTION + CDP_VERSION_TOO_OLD + CHROME_WEB_SECURITY_NOT_SUPPORTED + COMPONENT_FOLDER_REMOVED + CONFIG_FILES_LANGUAGE_CONFLICT + CONFIG_FILE_DEV_SERVER_IS_NOT_A_FUNCTION + CONFIG_FILE_INVALID_DEV_START_EVENT + CONFIG_FILE_INVALID_ROOT_CONFIG + CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT + CONFIG_FILE_INVALID_ROOT_CONFIG_E2E + CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT + CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E + CONFIG_FILE_MIGRATION_NEEDED + CONFIG_FILE_NOT_FOUND + CONFIG_FILE_REQUIRE_ERROR + CONFIG_FILE_SETUP_NODE_EVENTS_ERROR + CONFIG_FILE_UNEXPECTED_ERROR + CONFIG_VALIDATION_ERROR + CONFIG_VALIDATION_MSG_ERROR + COULD_NOT_FIND_SYSTEM_NODE + COULD_NOT_PARSE_ARGUMENTS + DASHBOARD_ALREADY_COMPLETE + DASHBOARD_API_RESPONSE_FAILED_RETRYING + DASHBOARD_CANCEL_SKIPPED_SPEC + DASHBOARD_CANNOT_CREATE_RUN_OR_INSTANCE + DASHBOARD_CANNOT_PROCEED_IN_PARALLEL + DASHBOARD_CANNOT_PROCEED_IN_SERIAL + DASHBOARD_CANNOT_UPLOAD_RESULTS + DASHBOARD_GRAPHQL_ERROR + DASHBOARD_INVALID_RUN_REQUEST + DASHBOARD_PARALLEL_DISALLOWED + DASHBOARD_PARALLEL_GROUP_PARAMS_MISMATCH + DASHBOARD_PARALLEL_REQUIRED + DASHBOARD_PROJECT_NOT_FOUND + DASHBOARD_RECORD_KEY_NOT_VALID + DASHBOARD_RUN_GROUP_NAME_NOT_UNIQUE + DASHBOARD_STALE_RUN + DASHBOARD_UNKNOWN_CREATE_RUN_WARNING + DASHBOARD_UNKNOWN_INVALID_REQUEST + DEFAULT_SUPPORT_FILE_NOT_FOUND + DEPRECATED_BEFORE_BROWSER_LAUNCH_ARGS + DUPLICATE_TASK_KEY + ERROR_READING_FILE + ERROR_WRITING_FILE + EXPERIMENTAL_COMPONENT_TESTING_REMOVED + EXPERIMENTAL_NETWORK_STUBBING_REMOVED + EXPERIMENTAL_RUN_EVENTS_REMOVED + EXPERIMENTAL_SAMESITE_REMOVED + EXPERIMENTAL_SHADOW_DOM_REMOVED + EXPERIMENTAL_STUDIO_REMOVED + EXTENSION_NOT_LOADED + FIREFOX_COULD_NOT_CONNECT + FIREFOX_GC_INTERVAL_REMOVED + FIREFOX_MARIONETTE_FAILURE + FIXTURE_NOT_FOUND + FOLDER_NOT_WRITABLE + FREE_PLAN_EXCEEDS_MONTHLY_PRIVATE_TESTS + FREE_PLAN_EXCEEDS_MONTHLY_TESTS + FREE_PLAN_IN_GRACE_PERIOD_EXCEEDS_MONTHLY_PRIVATE_TESTS + FREE_PLAN_IN_GRACE_PERIOD_EXCEEDS_MONTHLY_TESTS + FREE_PLAN_IN_GRACE_PERIOD_PARALLEL_FEATURE + INCOMPATIBLE_PLUGIN_RETRIES + INCORRECT_CI_BUILD_ID_USAGE + INDETERMINATE_CI_BUILD_ID + INTEGRATION_FOLDER_REMOVED + INVALID_CONFIG_OPTION + INVALID_CYPRESS_INTERNAL_ENV + INVALID_REPORTER_NAME + INVOKED_BINARY_OUTSIDE_NPM_MODULE + LEGACY_CONFIG_ERROR_DURING_MIGRATION + LEGACY_CONFIG_FILE + MIGRATION_ALREADY_OCURRED + MULTIPLE_SUPPORT_FILES_FOUND + NODE_VERSION_DEPRECATION_BUNDLED + NODE_VERSION_DEPRECATION_SYSTEM + NOT_LOGGED_IN + NO_DEFAULT_CONFIG_FILE_FOUND + NO_PROJECT_FOUND_AT_PROJECT_ROOT + NO_PROJECT_ID + NO_SPECS_FOUND + PAID_PLAN_EXCEEDS_MONTHLY_PRIVATE_TESTS + PARALLEL_FEATURE_NOT_AVAILABLE_IN_PLAN + PLAN_EXCEEDS_MONTHLY_TESTS + PLAN_IN_GRACE_PERIOD_RUN_GROUPING_FEATURE_USED + PLUGINS_FILE_CONFIG_OPTION_REMOVED + PLUGINS_RUN_EVENT_ERROR + PORT_IN_USE_LONG + PORT_IN_USE_SHORT + PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION + RECORDING_FROM_FORK_PR + RECORD_KEY_MISSING + RECORD_PARAMS_WITHOUT_RECORDING + RENAMED_CONFIG_OPTION + RENDERER_CRASHED + RUN_GROUPING_FEATURE_NOT_AVAILABLE_IN_PLAN + SETUP_NODE_EVENTS_DO_NOT_SUPPORT_DEV_SERVER + SETUP_NODE_EVENTS_INVALID_EVENT_NAME_ERROR + SETUP_NODE_EVENTS_IS_NOT_FUNCTION + SUPPORT_FILE_NOT_FOUND + TESTS_DID_NOT_START_FAILED + TESTS_DID_NOT_START_RETRYING + TEST_FILES_RENAMED + UNEXPECTED_BEFORE_BROWSER_LAUNCH_PROPERTIES + UNEXPECTED_INTERNAL_ERROR + UNEXPECTED_MUTATION_ERROR + UNSUPPORTED_BROWSER_VERSION + VIDEO_POST_PROCESSING_FAILED + VIDEO_RECORDING_FAILED +} + +"""Base error""" +type ErrorWrapper { + """The code frame to display in relation to the error""" + codeFrame: CodeFrame + + """The markdown formatted content associated with the ErrorTypeEnum""" + errorMessage: String! + + """Name of the error class""" + errorName: String! + + """ + The error stack of either the original error from the user or from where the internal Cypress error was created + """ + errorStack: String! + errorType: ErrorTypeEnum! + + """ + Whether the error came from user code, can be used to determine whether to open a stack trace by default + """ + isUserCodeError: Boolean! + + """ + Optional title of the error. Used to optionally display a title above the error + """ + title: String +} + +input FileDetailsInput { + column: Int + + """ + When we open a file we take a filePath, either relative to the project root, or absolute on disk + """ + filePath: String! + line: Int +} + +enum FileExtensionEnum { + js + ts +} + +"""Represents a file on the file system""" +type FileParts implements Node { + """ + Absolute path to file (e.g. /Users/jess/my-project/src/component/MySpec.test.tsx) + """ + absolute: String! + + """Full name of the file (e.g. MySpec.test.tsx)""" + baseName: String! + + """ + If provided, used to specify the column of the file to open in openFileInIDE + """ + column: Int + + """The contents of the file""" + contents: String! + + """The file's extension""" + fileExtension: String! + + """The first part of the file, without extensions (e.g. MySpec)""" + fileName: String! + + """Relay style Node ID field for the FileParts field""" + id: ID! + + """ + If provided, used to specify the line of the file to open in openFileInIDE + """ + line: Int + + """Full name of spec file (e.g. MySpec.test.tsx)""" + name: String! + + """Relative path to file (e.g. src/component/MySpec.test.tsx)""" + relative: String! +} + +enum FrontendFrameworkCategoryEnum { + react + vue +} + +enum FrontendFrameworkEnum { + crav4 + crav5 + nextjs + nuxtjs + react + vue2 + vue3 + vuecli4vue2 + vuecli4vue3 + vuecli5vue2 + vuecli5vue3 +} + +"""Error from generated spec""" +type GenerateSpecResponse { + """The currently opened project""" + currentProject: CurrentProject + + """The file that have just been scaffolded or the fileName that errored""" + generatedSpecResult: GeneratedSpecResult +} + +"""Error from generated spec""" +type GeneratedSpecError { + erroredCodegenCandidate: String! + fileName: String! +} + +union GeneratedSpecResult = GeneratedSpecError | ScaffoldedFile + +"""Git information about a spec file""" +type GitInfo { + """Last person to change the file in git""" + author: String + + """last modified as a pretty string, eg 2 days ago""" + lastModifiedHumanReadable: String + + """last modified timestamp, eg 2021-09-14 13:43:19 +1000""" + lastModifiedTimestamp: String + + """status type - created or modified""" + statusType: GitInfoStatusType +} + +enum GitInfoStatusType { + created + modified + unmodified +} + +"""A project which exists on the filesystem but has not been opened""" +type GlobalProject implements Node & ProjectLike { + """Relay style Node ID field for the GlobalProject field""" + id: ID! + + """Used to associate project with Cypress dashboard""" + projectId: String + + """Absolute path to the project on the filesystem""" + projectRoot: String! + title: String! +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + +"""local settings on a device-by-device basis""" +type LocalSettings { + availableEditors: [Editor!]! + preferences: LocalSettingsPreferences! +} + +"""local setting preferences""" +type LocalSettingsPreferences { + autoScrollingEnabled: Boolean + isSideNavigationOpen: Boolean + isSpecsListOpen: Boolean + preferredEditorBinary: String + proxyBypass: String + proxyServer: String + reporterWidth: Int + specListWidth: Int +} + +type ManualMigration implements Node { + """is the manual migration completed (all files are moved)""" + completed: Boolean! + + """files needing manual migration""" + files: [ManualMigrationFile!]! + + """Relay style Node ID field for the ManualMigration field""" + id: ID! +} + +type ManualMigrationFile implements Node { + """Relay style Node ID field for the ManualMigrationFile field""" + id: ID! + + """has the file been moved since opening the migration helper""" + moved: Boolean! + + """name of file to migrate""" + relative: String! +} + +"""Contains all data related to the 9.X to 10.0 migration UI""" +type Migration { + """the component folder path used to store components tests""" + componentFolder: String! + + """contents of the cypress.json file after conversion""" + configAfterCode: String! + + """contents of the cypress.json file before conversion""" + configBeforeCode: String! + + """the name of the config file after the migration""" + configFileNameAfter: String! + + """the name of the config file to be migrated""" + configFileNameBefore: String! + + """Steps filtered with the current context""" + filteredSteps: [MigrationStep!]! + + """whether component testing is set up in the migrated config or not""" + hasComponentTesting: Boolean! + + """whether the component folder is custom or not""" + hasCustomComponentFolder: Boolean! + + """whether the testFiles member is custom or not in component testing""" + hasCustomComponentTestFiles: Boolean! + + """whether the integration folder is custom or not""" + hasCustomIntegrationFolder: Boolean! + + """whether the testFiles member is custom or not in integration""" + hasCustomIntegrationTestFiles: Boolean! + + """Whether the project has Typescript""" + hasTypescript: Boolean + + """the integration folder path used to store e2e tests""" + integrationFolder: String! + + """List of files needing manual conversion""" + manualFiles: ManualMigration + + """All spec files after conversion""" + specFiles: [MigrationFile!]! + + """Support files needing automated rename""" + supportFiles: MigrationFile +} + +type MigrationFile { + after: MigrationFileData! + before: MigrationFileData! + testingType: TestingTypeEnum! +} + +type MigrationFileData implements Node { + """Relay style Node ID field for the MigrationFileData field""" + id: ID! + parts: [MigrationFilePart!]! + relative: String! +} + +type MigrationFilePart implements Node { + """is this part a folder or extension that needs migration""" + group: String + + """should highlight in migration UI""" + highlight: Boolean! + + """Relay style Node ID field for the MigrationFilePart field""" + id: ID! + + """part of filename""" + text: String! +} + +type MigrationRegexp { + """regexp to use to rename existing specs in component""" + afterComponent: String! + + """regexp to use to rename existing specs in e2e""" + afterE2E: String! + + """regexp to identify existing specs in component""" + beforeComponent: String! + + """regexp to identify existing specs in e2e""" + beforeE2E: String! +} + +"""Contains all data related to the 9.X to 10.0 migration UI""" +type MigrationStep implements Node { + """Relay style Node ID field for the MigrationStep field""" + id: ID! + + """Index of the step in the list""" + index: Int! + + """Has the current step been completed""" + isCompleted: Boolean! + + """This is the current step""" + isCurrentStep: Boolean! + + """Identifier of the step""" + name: MigrationStepEnum! +} + +enum MigrationStepEnum { + configFile + renameAuto + renameManual + renameSupport + setupComponent +} + +type Mutation { + """Add project to projects array and cache it""" + addProject( + """Whether to open the project when added""" + open: Boolean + path: String + ): Query + + """Clears the currently active project""" + clearCurrentProject: Query + clearCurrentTestingType: Query + + """Close active browser""" + closeBrowser: Boolean + + """Create a project in the dashboard and return its object""" + cloudProjectCreate(ciProviders: [String!], name: String!, orgId: ID!, public: Boolean!): CloudProject + + """Request access to an organization from a projectId""" + cloudProjectRequestAccess(projectSlug: String!): CloudProjectResult + completeSetup: Query + + """add the passed text to the local clipboard""" + copyTextToClipboard(text: String!): Boolean + + """ + Development only: Triggers or dismisses a prompted refresh by touching the file watched by our development scripts + """ + devRelaunch(action: DevRelaunchAction!): Boolean + + """Dismisses a warning displayed by the frontend""" + dismissWarning: Query + + """user has finished migration component specs - move to next step""" + finishedRenamingComponentSpecs: Query + + """Sets focus to the active browser window""" + focusActiveBrowserWindow: Boolean! + + """Generate spec from source""" + generateSpecFromSource(codeGenCandidate: String!, erroredCodegenCandidate: String, type: CodeGenType!): GenerateSpecResponse + + """Hides the launchpad windows""" + hideBrowserWindow: Boolean! + internal_clearAllProjectPreferencesCache: Boolean + internal_clearLatestProjectCache: Boolean + internal_clearProjectPreferencesCache(projectTitle: String!): Boolean + + """Launches project from open_project global singleton""" + launchOpenProject(specPath: String): CurrentProject + + """Sets the active browser""" + launchpadSetBrowser( + """ID of the browser that we want to set""" + id: ID! + ): CurrentProject + + """Auth with Cypress Dashboard""" + login: Query + + """Log out of Cypress Dashboard""" + logout: Query + + """Check if a give spec file will match the project spec pattern""" + matchesSpecPattern(specFile: String!): Boolean! + + """While migrating to 10+ skip manual rename step""" + migrateCloseManualRenameWatcher: Boolean + + """Merges the component testing config in cypress.config.{js,ts}""" + migrateComponentTesting: Query + + """Transforms cypress.json file into cypress.config.js file""" + migrateConfigFile: Query + + """While migrating to 10+ renames files to match the new .cy pattern""" + migrateRenameSpecs( + """specs to move - current name""" + after: [String!] + + """specs to move - current name""" + before: [String!] + skip: Boolean + ): Query + + """When the user decides to skip specs rename""" + migrateRenameSpecsFolder: Query + + """While migrating to 10+ launch renaming of support file""" + migrateRenameSupport: Query + + """While migrating to 10+ skip manual rename step""" + migrateSkipManualRename: Query + + """Open a path in preferred IDE""" + openDirectoryInIDE(path: String!): Boolean + openExternal(includeGraphqlPort: Boolean, url: String!): Boolean + + """Open a file on specified line and column in preferred IDE""" + openFileInIDE(input: FileDetailsInput!): Boolean + + """Open a path in the local file explorer""" + openInFinder(path: String!): Boolean + + """Ping configured Base URL""" + pingBaseUrl: Query + + """show the launchpad windows""" + reconfigureProject: Boolean! + + """Remove project from projects array and cache""" + removeProject(path: String!): Query + + """Reset the Auth State""" + resetAuthState: Query! + + """Resets errors and attempts to reload the config""" + resetErrorsAndLoadConfig: Query + + """ + Resets the latest version call to capture additional telemetry for the current user + """ + resetLatestVersionTelemetry: Boolean! + + """Reset the Wizard to the starting position""" + resetWizard: Boolean! + scaffoldIntegration: [ScaffoldedFile!]! + scaffoldTestingType: Query + setAndLoadCurrentTestingType(testingType: TestingTypeEnum!): Query + + """Set active project to run tests on""" + setCurrentProject(path: String!): Query + + """ + Update local preferences (also known as appData). The payload, `value`, should be a `JSON.stringified()` object of the new values you'd like to persist. Example: `setPreferences (value: JSON.stringify({ lastOpened: Date.now() }))` + """ + setPreferences(value: String!): Query + + """Set the projectId field in the config file of the current project""" + setProjectIdInConfigFile(projectId: String!): Query + + """Save the projects preferences to cache""" + setProjectPreferences(testingType: TestingTypeEnum!): Query! + + """Save the prompt-shown state for this project""" + setPromptShown(slug: String!): Boolean + + """Set the selected testing type, and reconfigure the project""" + setTestingTypeAndReconfigureProject(isApp: Boolean!, testingType: TestingTypeEnum!): Query + + """Switch Testing type and relaunch browser""" + switchTestingTypeAndRelaunch(testingType: TestingTypeEnum!): Boolean + + """Updates the different fields of the wizard data store""" + wizardUpdate(input: WizardUpdateInput!): Wizard +} + +"""Implements the Relay Node spec""" +interface Node { + """Globally unique identifier representing a concrete GraphQL ObjectType""" + id: ID! +} + +enum PackageManagerEnum { + npm + pnpm + yarn +} + +""" +PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo +""" +type PageInfo { + """ + The cursor corresponding to the last nodes in edges. Null if the connection is empty. + """ + endCursor: String + + """ + Used to indicate whether more edges exist following the set defined by the clients arguments. + """ + hasNextPage: Boolean! + + """ + Used to indicate whether more edges exist prior to the set defined by the clients arguments. + """ + hasPreviousPage: Boolean! + + """ + The cursor corresponding to the first nodes in edges. Null if the connection is empty. + """ + startCursor: String +} + +enum PluginsState { + error + initialized + initializing + uninitialized +} + +"""Common base fields inherited by GlobalProject / CurrentProject""" +interface ProjectLike { + """Used to associate project with Cypress dashboard""" + projectId: String + + """Absolute path to the project on the filesystem""" + projectRoot: String! + title: String! +} + +"""Preferences specific to a project""" +type ProjectPreferences { + """The preferred testing type to start in""" + testingType: String +} + +"""The root "Query" type containing all entry fields for our querying""" +type Query { + """The latest state of the auth process""" + authState: AuthState! + baseError: ErrorWrapper + cachedUser: CachedUser + + """Returns an object conforming to the Relay spec""" + cloudNode( + """An ID for a Node conforming to the Relay spec""" + id: ID! + ): Node + + """Lookup an individual project by the slug""" + cloudProjectBySlug(slug: String!): CloudProjectResult + + """Lookup a list of projects by their slug""" + cloudProjectsBySlugs( + """A list of Project slugs""" + slugs: [String!]! + ): [CloudProjectResult] + + """A user within the Cypress Cloud""" + cloudViewer: CloudUser + + """The currently opened project""" + currentProject: CurrentProject + + """The state of any info related to local development of the runner""" + dev: DevState! + + """Whether the app is in global mode or not""" + isInGlobalMode: Boolean! + + """local settings on a device-by-device basis""" + localSettings: LocalSettings! + + """Metadata about the migration, null if we aren't showing it""" + migration: Migration + + """Whether the project was specified from the --project flag""" + projectRootFromCI: Boolean! + + """All known projects for the app""" + projects: [ProjectLike!]! + + """The files that have just been scaffolded""" + scaffoldedFiles: [ScaffoldedFile!] + + """Previous versions of cypress and their release date""" + versions: VersionData + + """A list of warnings""" + warnings: [ErrorWrapper!]! + + """Metadata about the wizard""" + wizard: Wizard! +} + +"""A file that we just added to the filesystem during project setup""" +type ScaffoldedFile { + """Info about the file we just scaffolded""" + description: String! + + """Info about the file""" + file: FileParts! + + """Info about the field""" + status: WizardConfigFileStatusEnum! +} + +"""Represents a spec on the file system""" +type Spec implements Node { + """ + Absolute path to spec (e.g. /Users/jess/my-project/src/component/MySpec.test.tsx) + """ + absolute: String! + + """Full name of spec file (e.g. MySpec.test.tsx)""" + baseName: String! + + """The file extension (e.g. tsx, jsx)""" + fileExtension: String! + + """The first part of the file, without extensions (e.g. MySpec)""" + fileName: String! + + """Git information about the spec file""" + gitInfo: GitInfo + + """Relay style Node ID field for the Spec field""" + id: ID! + + """Full name of spec file (e.g. MySpec.test.tsx)""" + name: String! + + """Relative path to spec (e.g. src/component/MySpec.test.tsx)""" + relative: String! + + """ + The spec file's extension, including "spec" pattern (e.g. .spec.tsx, -spec.tsx, -test.tsx) + """ + specFileExtension: String! + + """Type of spec (e.g. component | integration)""" + specType: SpecType! +} + +enum SpecType { + component + integration +} + +type Subscription { + """Triggered when the auth state changes""" + authChange: Query + + """Issued when the current branch of a project changes""" + branchChange: CurrentProject + + """Status of the currently opened browser""" + browserStatusChange: CurrentProject + + """ + Triggered when there is a change to the info associated with the cloud project (org added, project added) + """ + cloudViewerChange: Query + + """Issued for internal development changes""" + devChange: DevState + + """ + When the git info has refreshed for some or all of the specs, we fire this event with the specs updated + """ + gitInfoChange: [Spec] + + """Issued when the watched specs for the project changes""" + specsChange: CurrentProject +} + +"""The bundlers that we can use with Cypress""" +enum SupportedBundlers { + vite + webpack4 + webpack5 +} + +"""The packages for bundlers that we can use with Cypress""" +enum SupportedPackage { + vite + webpack +} + +enum TestingTypeEnum { + component + e2e +} + +type TestingTypeInfo implements Node { + description: String! + + """Relay style Node ID field for the TestingTypeInfo field""" + id: ID! + title: String! + type: TestingTypeEnum! +} + +"""Version of Cypress and release date""" +type Version { + """unique id""" + id: String! + + """Release date as an iso8601 timestamp""" + released: String! + + """Version number (follows semantic versioning)""" + version: String! +} + +"""Version of Cypress and release date""" +type VersionData { + """current version of cypress you are using""" + current: Version! + + """latest version of cypress""" + latest: Version! +} + +""" +The Wizard is a container for any state associated with initial onboarding to Cypress +""" +type Wizard { + """All of the bundlers to choose from""" + allBundlers: [WizardBundler!]! + + """All of the languages to choose from""" + allLanguages: [WizardCodeLanguage!]! + bundler: WizardBundler + framework: WizardFrontendFramework + + """All of the component testing frameworks to choose from""" + frameworks: [WizardFrontendFramework!]! + + """Command to install required command""" + installDependenciesCommand: String + + """The list of packages to install that are currently installed""" + installedPackages: [String!] + language: WizardCodeLanguage + + """ + A list of packages to install, null if we have not chosen both a framework and bundler + """ + packagesToInstall: [WizardNpmPackage!] +} + +"""Wizard bundler""" +type WizardBundler implements Node { + """Relay style Node ID field for the WizardBundler field""" + id: ID! + + """Whether this is the detected bundler""" + isDetected: Boolean! + + """Whether this is the selected framework bundler""" + isSelected: Boolean + + """Display name of the bundler""" + name: String! + + """Name of package on npm""" + package: SupportedPackage! + + """The name of the framework""" + type: SupportedBundlers! +} + +""" +A code language that the user can choose from to create their cypress.config +""" +type WizardCodeLanguage implements Node { + """Relay style Node ID field for the WizardCodeLanguage field""" + id: ID! + + """Whether this is the detected language""" + isDetected: Boolean! + + """Whether this is the selected language in the wizard""" + isSelected: Boolean! + + """The name of the language""" + name: String! + + """The key of the language""" + type: CodeLanguageEnum! +} + +enum WizardConfigFileStatusEnum { + changes + error + skipped + valid +} + +"""A frontend framework that we can setup within the app""" +type WizardFrontendFramework implements Node { + """Classification or label of framework. e.g. React, Vue, or Other""" + category: FrontendFrameworkCategoryEnum! + + """Relay style Node ID field for the WizardFrontendFramework field""" + id: ID! + + """Whether this is the detected framework""" + isDetected: Boolean! + + """Whether this is the selected framework in the wizard""" + isSelected: Boolean! + + """The name of the framework""" + name: String! + + """All of the supported bundlers for this framework""" + supportedBundlers: [WizardBundler!]! + + """The name of the framework""" + type: FrontendFrameworkEnum! +} + +"""Details about an NPM Package listed during the wizard install""" +type WizardNpmPackage implements Node { + description: String! + + """Relay style Node ID field for the WizardNpmPackage field""" + id: ID! + + """The package name that you would npm install""" + name: String! + package: String! +} + +input WizardUpdateInput { + bundler: SupportedBundlers + codeLanguage: CodeLanguageEnum + framework: FrontendFrameworkEnum +} diff --git a/packages/graphql/src/index.ts b/packages/graphql/src/index.ts new file mode 100644 index 0000000000..bf523d07fd --- /dev/null +++ b/packages/graphql/src/index.ts @@ -0,0 +1,7 @@ +export { graphqlSchema } from './schema' + +export { execute, parse, print } from 'graphql' + +export { remoteSchemaWrapped } from './stitching/remoteSchemaWrapped' + +export type { RemoteExecutionRoot } from './stitching/remoteSchemaExecutor' diff --git a/packages/graphql/src/makeGraphQLServer.ts b/packages/graphql/src/makeGraphQLServer.ts new file mode 100644 index 0000000000..a1f0705421 --- /dev/null +++ b/packages/graphql/src/makeGraphQLServer.ts @@ -0,0 +1,289 @@ +import express, { Request } from 'express' +import type { AddressInfo, Socket } from 'net' +import { DataContext, getCtx, globalPubSub, GraphQLRequestInfo } from '@packages/data-context' +import pDefer from 'p-defer' +import cors from 'cors' +import { SocketIOServer } from '@packages/socket' +import type { Server } from 'http' +import { graphqlHTTP } from 'express-graphql' +import serverDestroy from 'server-destroy' +import send from 'send' +import { getPathToDist } from '@packages/resolve-dist' +import httpProxy from 'http-proxy' +import debugLib from 'debug' +import { Server as WebSocketServer } from 'ws' +import { useServer } from 'graphql-ws/lib/use/ws' + +import { graphqlSchema } from './schema' +import { DefinitionNode, DocumentNode, execute, Kind, OperationDefinitionNode, OperationTypeNode, parse } from 'graphql' + +const debug = debugLib(`cypress-verbose:graphql:operation`) + +const IS_DEVELOPMENT = process.env.CYPRESS_INTERNAL_ENV !== 'production' + +let gqlSocketServer: SocketIOServer +let gqlServer: Server + +globalPubSub.on('reset:data-context', (ctx) => { + ctx.setGqlServer(gqlServer) + ctx.setGqlSocketServer(gqlSocketServer) +}) + +export async function makeGraphQLServer () { + const dfd = pDefer() + const app = express() + + app.use(cors()) + + app.get('/cloud-notification', (req, res) => { + const ctx = getCtx() + + const operationName = req.query.operationName + + if (!operationName || Array.isArray(operationName)) { + res.sendStatus(200) + + return + } + + switch (operationName) { + case 'orgCreated': + ctx.emitter.cloudViewerChange() + break + + default: + break + } + + res.sendStatus(200) + }) + + app.use('/__launchpad/graphql/:operationName?', graphQLHTTP) + + function makeProxy (): express.Handler { + if (process.env.CYPRESS_INTERNAL_VITE_DEV) { + const viteProxy = httpProxy.createProxyServer({ + target: `http://localhost:${process.env.CYPRESS_INTERNAL_VITE_LAUNCHPAD_PORT}/`, + }) + + return (req, res) => { + viteProxy.web(req, res, {}, (e) => {}) + } + } + + return (req, res) => { + send(req, req.params[0] ?? '', { + root: getPathToDist('launchpad'), + }).pipe(res) + } + } + + app.get('/__launchpad/*', makeProxy()) + + const graphqlPort = process.env.CYPRESS_INTERNAL_GRAPHQL_PORT + + let srv: Server + + function listenCallback () { + const ctx = getCtx() + const port = (srv.address() as AddressInfo).port + + const endpoint = `http://localhost:${port}/__launchpad/graphql` + + if (process.env.NODE_ENV === 'development') { + /* eslint-disable-next-line no-console */ + console.log(`GraphQL server is running at ${endpoint}`) + } + + debug(`GraphQL Server at ${endpoint}`) + + gqlServer = srv + + ctx.setGqlServer(srv) + + dfd.resolve(port) + } + + srv = graphqlPort ? app.listen(graphqlPort, listenCallback) : app.listen(listenCallback) + + serverDestroy(srv) + + gqlSocketServer = new SocketIOServer(srv, { + path: '/__launchpad/socket', + transports: ['websocket'], + }) + + graphqlWS(srv, '/__launchpad/graphql-ws') + + gqlSocketServer.on('connection', (socket) => { + socket.on('graphql:request', handleGraphQLSocketRequest) + }) + + getCtx().setGqlSocketServer(gqlSocketServer) + + return dfd.promise +} + +interface GraphQLSocketPayload { + query: string + variables?: Record + operationName?: string +} + +// TODO: replace this w/ persisted queries +/** + * Handles the GraphQL operation run over WebSockets, + * rather than HTTP to clear up the console from extra chatter + * that doesn't originate from the users' web app. + * @param uid + * @param data + * @param callback + */ +export async function handleGraphQLSocketRequest (uid: string, payload: string, callback: Function) { + try { + const operation = JSON.parse(payload) as GraphQLSocketPayload + const context = getCtx() + const document = parse(operation.query) + const result = await execute({ + operationName: operation.operationName, + variableValues: operation.variables, + document, + schema: graphqlSchema, + contextValue: graphqlRequestContext({ + app: 'app', + context, + document, + variables: operation.variables ?? null, + }), + }) + + callback(result) + } catch (e) { + callback({ data: null, errors: [e] }) + } +} + +/** + * Creates a new WSServer conforming to the GraphQL over Websocket protocol: + * https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md + * + * @param httpServer The http server we are utilizing for the websocket + * @param targetRoute Route to target in the server upgrade event + * @returns Disposable Function to cleanup the created server resource + */ +export const graphqlWS = (httpServer: Server, targetRoute: string) => { + const graphqlWs = new WebSocketServer({ noServer: true }) + + httpServer.on('upgrade', (req, socket: Socket, head) => { + if (req.url.startsWith(targetRoute)) { + return graphqlWs.handleUpgrade(req, socket, head, (client) => { + graphqlWs.emit('connection', client, req) + }) + } + }) + + useServer({ + schema: graphqlSchema, + context: () => getCtx(), + }, graphqlWs) + + return graphqlWs +} + +/** + * An Express middleware function handler which can be added to + * routes expected to service a GraphQL request from an HTTP client. + */ +export const graphQLHTTP = graphqlHTTP((req, res, params) => { + const context = getCtx() + let document: DocumentNode | undefined + + // Parse the query ahead-of-time, so we can use in the graphqlRequestContext + try { + // @ts-expect-error + document = parse(params.query) + } catch { + // error will be re-thrown in customParseFn below + } + + return { + schema: graphqlSchema, + graphiql: IS_DEVELOPMENT, + context: params && document ? graphqlRequestContext({ + req: req as Request, + context, + document, + variables: params.variables, + }) : undefined, + customParseFn: (source) => { + // No need to re-parse if we have a document, otherwise re-parse to throw the error + return document ?? parse(source) + }, + customExecuteFn: (args) => { + const date = new Date() + const prefix = `${args.operationName ?? '(anonymous)'}` + + return Promise.resolve(execute(args)).then((val) => { + debug(`${prefix} completed in ${new Date().valueOf() - date.valueOf()}ms with ${val.errors?.length ?? 0} errors`) + + return val + }) + }, + } +}) + +interface GraphQLRequestContextOptions { + app?: 'launchpad' | 'app' + req?: Request + context: DataContext + document: DocumentNode + variables: Record | null +} + +/** + * Since the DataContext is considered a singleton throughout the electron app process, + * we create a Proxy object for it, adding metadata associated each GraphQL operation. + * This is used in middleware, such as the `nexusDeferIfNotLoadedPlugin`, to associate + * remote requests to operations needing to be refetched on the client. + */ +function graphqlRequestContext (options: GraphQLRequestContextOptions) { + const app = options.app ?? (options.req?.originalUrl.startsWith('/__launchpad') ? 'launchpad' : 'app') + + const primaryOperation = getPrimaryOperation(options.document) + + const requestInfo: GraphQLRequestInfo = { + app, + operation: (primaryOperation?.kind ?? 'query') as OperationTypeNode, + document: options.document, + headers: options.req?.headers ?? {}, + variables: options.variables, + operationName: primaryOperation?.name?.value ?? null, + } + + debug('Creating context for %s, operation %s', app, primaryOperation?.name?.value) + + return new Proxy(options.context, { + get (target, p, receiver) { + if (p === 'graphqlRequestInfo') { + return requestInfo + } + + if (p === 'actions' && IS_DEVELOPMENT && requestInfo.operation === 'query') { + throw new Error( + `Cannot access ctx.${p} within a query, only within mutations / outside of a GraphQL request\n` + + `Seen in operation: ${requestInfo.operationName}`, + ) + } + + return Reflect.get(target, p, receiver) + }, + }) +} + +function getPrimaryOperation (query: DocumentNode): OperationDefinitionNode | undefined { + return query.definitions.find(isOperationDefinitionNode) +} + +function isOperationDefinitionNode (node: DefinitionNode): node is OperationDefinitionNode { + return node.kind === Kind.OPERATION_DEFINITION +} diff --git a/packages/graphql/src/plugins/index.ts b/packages/graphql/src/plugins/index.ts new file mode 100644 index 0000000000..6141bfbda2 --- /dev/null +++ b/packages/graphql/src/plugins/index.ts @@ -0,0 +1,8 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './nexusDebugFieldPlugin' +export * from './nexusDeferIfNotLoadedPlugin' +export * from './nexusMutationErrorPlugin' +export * from './nexusNodePlugin' +export * from './nexusSlowGuardPlugin' diff --git a/packages/graphql/src/plugins/nexusDebugFieldPlugin.ts b/packages/graphql/src/plugins/nexusDebugFieldPlugin.ts new file mode 100644 index 0000000000..cb37927afb --- /dev/null +++ b/packages/graphql/src/plugins/nexusDebugFieldPlugin.ts @@ -0,0 +1,40 @@ +import { plugin } from 'nexus' +import debugLib from 'debug' +import { pathToArray } from 'graphql/jsutils/Path' + +const debugField = debugLib(`cypress-verbose:graphql:fields`) + +const SLOW_FIELD_THRESHOLD = 100 // Log any field taking longer than 100ms + +const delta = (d: Date) => { + return new Date().valueOf() - d.valueOf() +} + +export const nexusDebugLogPlugin = plugin({ + name: 'NexusDebugLogPlugin', + description: 'Wraps the resolve & adds debug logs for operations, and for fields if there is a slow execution.', + // When we create a field resolver, we can wrap it in a field + onCreateFieldResolver (info) { + // For fields, we only want to log if the field takes longer than SLOW_FIELD_THRESHOLD to execute. + // Also log if it's hanging for some reason + return (root, args, ctx, info, next) => { + const start = new Date() + const resolvePath = pathToArray(info.path) + + function maybeLog (suffix = '') { + if (delta(start) > SLOW_FIELD_THRESHOLD) { + debugField(`${info.operation.operation} ${info.operation.name?.value ?? `(anonymous)`} took ${delta(start)}ms to resolve ${JSON.stringify(resolvePath)}${suffix}`) + } + } + + return plugin.completeValue(next(root, args, ctx, info), (val) => { + maybeLog() + + return val + }, (err) => { + maybeLog() + throw err + }) + } + }, +}) diff --git a/packages/graphql/src/plugins/nexusDeferIfNotLoadedPlugin.ts b/packages/graphql/src/plugins/nexusDeferIfNotLoadedPlugin.ts new file mode 100644 index 0000000000..ae6509dfbe --- /dev/null +++ b/packages/graphql/src/plugins/nexusDeferIfNotLoadedPlugin.ts @@ -0,0 +1,122 @@ +import { plugin } from 'nexus' +import debugLib from 'debug' +import { getNamedType, isNonNullType } from 'graphql' +import type { DataContext } from '@packages/data-context' +import { remoteSchema } from '../stitching/remoteSchema' + +const NO_RESULT = {} +// 2ms should be enough time to resolve from the local cache of the +// cloudUrqlClient in CloudDataSource +const RACE_MAX_EXECUTION_MS = 2 +const IS_DEVELOPMENT = process.env.CYPRESS_INTERNAL_ENV !== 'production' +const debug = debugLib('cypress:graphql:nexusDeferIfNotLoadedPlugin') + +/** + * This plugin taps into each of the requests and checks for the existence + * of a "Cloud" prefixed type. When we see these, we know that we're dealing + * with a remote API. We can also specify `deferIfNotLoaded: true` on the Nexus definition + * to indicate that this is a remote request, such as resolving the "versions" field + */ +export const nexusDeferIfNotLoadedPlugin = plugin({ + name: 'nexusDeferIfNotLoadedPlugin', + fieldDefTypes: 'deferIfNotLoaded?: true', + onCreateFieldResolver (def) { + const { name: parentTypeName } = def.parentTypeConfig + + // Don't ever need to do this on Subscription / Mutation fields. + if (parentTypeName === 'Mutation' || parentTypeName === 'Subscription') { + return + } + + // Also don't need to if the type is in the cloud schema, (and isn't a Query) since these don't + // actually need to resolve themselves, they're resolved from the remote request + if (parentTypeName !== 'Query' && remoteSchema.getType(parentTypeName)) { + return + } + + // Specified w/ deferIfNotLoaded: true on the field definition + const shouldDeferIfNotLoaded = Boolean(def.fieldConfig.extensions?.nexus?.config.deferIfNotLoaded) + + // Fields where type: 'Cloud*', e.g. 'cloudViewer' which is type: 'CloudUser' + const isEligibleCloudField = getNamedType(def.fieldConfig.type).name.startsWith('Cloud') + + if (!isEligibleCloudField && !shouldDeferIfNotLoaded) { + return + } + + const qualifiedField = `${def.parentTypeConfig.name}.${def.fieldConfig.name}` + + // We should never allow a non-null query type, this is an error should be caught at development time + if (isNonNullType(def.fieldConfig.type)) { + throw new Error(`Cannot add nexusDeferIfNotLoadedPlugin to non-nullable field ${qualifiedField}`) + } + + debug(`Adding nexusDeferIfNotLoadedPlugin for %s`, qualifiedField) + + return async (source, args, ctx: DataContext, info, next) => { + // Don't need to race Mutations / Subscriptions, which can return types containing these fields + // these can just call through and don't need to be resolved immediately, because there's an expectation + // of potential delay built-in to these contracts + if ( + info.operation.operation === 'mutation' || + info.operation.operation === 'subscription' + ) { + return next(source, args, ctx, info) + } + + debug(`Racing execution for %s`, qualifiedField) + + let didRace = false + + const raceResult: unknown = await Promise.race([ + new Promise((resolve) => setTimeout(() => resolve(NO_RESULT), RACE_MAX_EXECUTION_MS)), + Promise.resolve(next(source, args, ctx, info)).then((result) => { + if (!didRace) { + debug(`Racing %s resolved immediately`, qualifiedField) + + return result + } + + debug(`Racing %s eventually resolved with %o`, qualifiedField, result, ctx.graphqlRequestInfo?.operationName) + + // If we raced the query, and this looks like a client request we can re-execute, + // we will look to do so. + if (ctx.graphqlRequestInfo?.operationName) { + // We don't want to notify the client if we see a refetch header, and we want to warn if + // we raced twice, as this means we're not caching the data properly + if (ctx.graphqlRequestInfo.headers['x-cypress-graphql-refetch']) { + // If we've hit this during a refetch, but the refetch was unrelated to the original request, + // that's fine, it just means that we might receive a notification to refetch in the future for the other field + if (IS_DEVELOPMENT && ctx.graphqlRequestInfo.headers['x-cypress-graphql-refetch'] === `${ctx.graphqlRequestInfo?.operationName}.${qualifiedField}`) { + // eslint-disable-next-line no-console + console.error(new Error(` + It looks like we hit the Promise.race while re-executing the operation ${ctx.graphqlRequestInfo.operationName} + this means that we sent the client a signal to refetch, but the data wasn't stored when it did. + This likely means we're not caching the result of the the data properly. + `)) + } + } else { + debug(`Notifying app %s, %s of updated field %s`, ctx.graphqlRequestInfo.app, ctx.graphqlRequestInfo.operationName, qualifiedField) + ctx.emitter.notifyClientRefetch(ctx.graphqlRequestInfo.app, ctx.graphqlRequestInfo.operationName, qualifiedField, ctx.graphqlRequestInfo.variables) + } + } else { + debug(`No operation to notify of result for %s`, qualifiedField) + } + }).catch((e) => { + debug(`Remote execution error %o`, e) + + return null + }), + ]) + + if (raceResult === NO_RESULT) { + debug(`%s did not resolve immediately`, qualifiedField) + didRace = true + + return null + } + + return raceResult + } + }, +}) diff --git a/packages/graphql/src/plugins/nexusMutationErrorPlugin.ts b/packages/graphql/src/plugins/nexusMutationErrorPlugin.ts new file mode 100644 index 0000000000..9241e03f12 --- /dev/null +++ b/packages/graphql/src/plugins/nexusMutationErrorPlugin.ts @@ -0,0 +1,35 @@ +import { plugin } from 'nexus' +import { getError } from '@packages/errors' +import type { DataContext } from '@packages/data-context' +import { getNamedType, isObjectType } from 'graphql' + +export const mutationErrorPlugin = plugin({ + name: 'MutationErrorPlugin', + description: 'Wraps any mutation fields and handles any uncaught errors', + onCreateFieldResolver: (def) => { + if (def.parentTypeConfig.name !== 'Mutation') { + return + } + + return (source, args, ctx: DataContext, info, next) => { + return plugin.completeValue(next(source, args, ctx, info), (v) => v, (err) => { + ctx.update((d) => { + d.baseError = { + cypressError: err.isCypressErr + ? err + : getError('UNEXPECTED_MUTATION_ERROR', def.fieldConfig.name, args, err), + } + }) + + const returnType = getNamedType(info.returnType) + + // If we're returning a query, we're getting the "baseError" here anyway + if (isObjectType(returnType) && returnType.name === 'Query') { + return {} + } + + throw err + }) + } + }, +}) diff --git a/packages/graphql/src/plugins/nexusNodePlugin.ts b/packages/graphql/src/plugins/nexusNodePlugin.ts new file mode 100644 index 0000000000..634109ce7f --- /dev/null +++ b/packages/graphql/src/plugins/nexusNodePlugin.ts @@ -0,0 +1,48 @@ +import { FieldResolver, plugin } from 'nexus' + +// We know this is a valid node typename +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type $ValidatedByGraphQL = any; + +export const nodePlugin = plugin({ + name: 'NodePlugin', + objectTypeDefTypes: ` + node?: (TypeName extends keyof NexusGenRootTypes ? keyof NexusGenRootTypes[TypeName] : never) | core.FieldResolver`, + onObjectDefinition (def, { node }) { + if (node != null) { + let resolveFn: FieldResolver + + if (typeof node === 'function') { + resolveFn = (root, args, ctx, info) => { + return ctx.makeId( + def.typeName as $ValidatedByGraphQL, + node(root, args, ctx, info), + ) + } + } else if (typeof node === 'string') { + resolveFn = (root, args, ctx) => { + return ctx.makeId( + def.typeName as $ValidatedByGraphQL, + assertNonNull(root[node]), + ) + } + } else { + throw new Error(`Expected ${String(node)} to be a string or fn, saw.`) + } + + def.implements('Node') + def.nonNull.id('id', { + description: `Relay style Node ID field for the ${def.typeName} field`, + resolve: resolveFn, + }) + } + }, +}) + +function assertNonNull (val: T | null | undefined): T { + if (val == null) { + throw new Error(`Expected val to be non-null. This should never happen`) + } + + return val as T +} diff --git a/packages/graphql/src/plugins/nexusSlowGuardPlugin.ts b/packages/graphql/src/plugins/nexusSlowGuardPlugin.ts new file mode 100644 index 0000000000..a4552901e9 --- /dev/null +++ b/packages/graphql/src/plugins/nexusSlowGuardPlugin.ts @@ -0,0 +1,47 @@ +import { plugin } from 'nexus' +import { isPromiseLike, pathToArray } from 'nexus/dist/utils' +import chalk from 'chalk' + +const HANGING_RESOLVER_THRESHOLD = 15 + +export const nexusSlowGuardPlugin = plugin({ + name: 'NexusSlowGuard', + description: 'If there is a very slow / hanging execution of a field, we detect/log to the console it in development', + fieldDefTypes: 'slowLogThreshold?: number | false', + // When we create a field resolver, we can wrap it in a field + onCreateFieldResolver (field) { + const threshold = (field.fieldConfig.extensions?.nexus?.config.slowLogThreshold ?? HANGING_RESOLVER_THRESHOLD) as number | false + + return (root, args, ctx, info, next) => { + // Don't worry about slowness in Mutations / Subscriptions, these aren't blocking the execution of initial load + if (info.operation.operation === 'mutation' || info.operation.operation === 'subscription') { + return next(root, args, ctx, info) + } + + const result = next(root, args, ctx, info) + + if (isPromiseLike(result) && threshold !== false) { + const resolvePath = pathToArray(info.path) + const hanging = setTimeout(() => { + const operationId = `${info.operation.operation} ${info.operation.name?.value ?? `(anonymous)`}` + + if (process.env.CYPRESS_INTERNAL_ENV !== 'production') { + // eslint-disable-next-line no-console + console.error(chalk.red(`\n\nNexusSlowGuard: Taking more than ${threshold}ms to execute ${JSON.stringify(resolvePath)} for ${operationId}\n\n`)) + } + }, threshold) + + return plugin.completeValue(result, (val) => { + clearTimeout(hanging) + + return val + }, (err) => { + clearTimeout(hanging) + throw err + }) + } + + return result + } + }, +}) diff --git a/packages/graphql/src/schema.ts b/packages/graphql/src/schema.ts new file mode 100644 index 0000000000..5c91b68ed6 --- /dev/null +++ b/packages/graphql/src/schema.ts @@ -0,0 +1,55 @@ +import path from 'path' +import { makeSchema, connectionPlugin } from 'nexus' + +import * as schemaTypes from './schemaTypes/' +import { nodePlugin } from './plugins/nexusNodePlugin' +import { remoteSchemaWrapped } from './stitching/remoteSchemaWrapped' +import { mutationErrorPlugin, nexusDebugLogPlugin, nexusSlowGuardPlugin, nexusDeferIfNotLoadedPlugin } from './plugins' + +const isCodegen = Boolean(process.env.CYPRESS_INTERNAL_NEXUS_CODEGEN) + +export const graphqlSchema = makeSchema({ + types: schemaTypes, + shouldGenerateArtifacts: isCodegen, + shouldExitAfterGenerateArtifacts: isCodegen, + outputs: { + typegen: { + outputPath: path.join(__dirname, 'gen/nxs.gen.ts'), + declareInputs: true, + }, + schema: path.join(__dirname, '..', 'schemas', 'schema.graphql'), + }, + contextType: { + module: '@packages/data-context', + export: 'DataContext', + }, + mergeSchema: { + schema: remoteSchemaWrapped, + skipFields: { + Mutation: ['test'], + }, + }, + plugins: [ + nexusSlowGuardPlugin, + nexusDeferIfNotLoadedPlugin, + nexusDebugLogPlugin, + mutationErrorPlugin, + connectionPlugin({ + nonNullDefaults: { + output: true, + }, + }), + nodePlugin, + ], + formatTypegen (content, type) { + if (type === 'schema') { + return content + } + + // TODO(tim): fix in nexus to prevent the regex + return `/* eslint-disable */\n${content.replace(/\.js"/g, '"')}` + }, + features: { + abstractTypeRuntimeChecks: false, + }, +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserFamilyEnum.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserFamilyEnum.ts new file mode 100644 index 0000000000..cb978c3f38 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserFamilyEnum.ts @@ -0,0 +1,7 @@ +import { BROWSER_FAMILY } from '@packages/types' +import { enumType } from 'nexus' + +export const BrowserFamilyEnum = enumType({ + name: 'BrowserFamily', + members: BROWSER_FAMILY, +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserStatus.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserStatus.ts new file mode 100644 index 0000000000..26965e79d5 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-BrowserStatus.ts @@ -0,0 +1,7 @@ +import { BROWSER_STATUS } from '@packages/types' +import { enumType } from 'nexus' + +export const BrowserStatusEnum = enumType({ + name: 'BrowserStatus', + members: BROWSER_STATUS, +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-CodeGenTypeEnum.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-CodeGenTypeEnum.ts new file mode 100644 index 0000000000..765c34ef61 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-CodeGenTypeEnum.ts @@ -0,0 +1,6 @@ +import { enumType } from 'nexus' + +export const CodeGenTypeEnum = enumType({ + name: 'CodeGenType', + members: ['component', 'e2e', 'scaffoldIntegration'], +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-ErrorTypeEnum.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-ErrorTypeEnum.ts new file mode 100644 index 0000000000..777877a500 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-ErrorTypeEnum.ts @@ -0,0 +1,7 @@ +import { enumType } from 'nexus' +import { AllCypressErrors } from '@packages/errors' + +export const ErrorTypeEnum = enumType({ + name: 'ErrorTypeEnum', + members: Object.keys(AllCypressErrors), +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-FileExtensionEnum.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-FileExtensionEnum.ts new file mode 100644 index 0000000000..8b4d9e4b8b --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-FileExtensionEnum.ts @@ -0,0 +1,6 @@ +import { enumType } from 'nexus' + +export const FileExtensionEnum = enumType({ + name: 'FileExtensionEnum', + members: ['js', 'ts'], +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-ProjectEnums.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-ProjectEnums.ts new file mode 100644 index 0000000000..b655d90945 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-ProjectEnums.ts @@ -0,0 +1,7 @@ +import { PLUGINS_STATE } from '@packages/types' +import { enumType } from 'nexus' + +export const PluginsStateEnum = enumType({ + name: 'PluginsState', + members: PLUGINS_STATE, +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-SpecEnum.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-SpecEnum.ts new file mode 100644 index 0000000000..67c23a99cb --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-SpecEnum.ts @@ -0,0 +1,10 @@ +import { enumType } from 'nexus' + +export const SPEC_TYPE = ['component', 'integration'] as const + +export type SpecType = typeof SPEC_TYPE[number] + +export const SpecTypeEnum = enumType({ + name: 'SpecType', + members: SPEC_TYPE, +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts new file mode 100644 index 0000000000..7f363d1ed9 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts @@ -0,0 +1,40 @@ +import { CODE_LANGUAGES } from '@packages/types' +import { BUNDLERS, FRONTEND_FRAMEWORKS } from '@packages/scaffold-config' +import { enumType } from 'nexus' + +export const SupportedBundlerEnum = enumType({ + name: 'SupportedBundlers', + description: 'The bundlers that we can use with Cypress', + members: BUNDLERS.map((t) => t.type), +}) + +export const SupportedPackageEnum = enumType({ + name: 'SupportedPackage', + description: 'The packages for bundlers that we can use with Cypress', + members: BUNDLERS.map((t) => t.package), +}) + +export const WizardConfigFileStatusEnum = enumType({ + name: 'WizardConfigFileStatusEnum', + members: ['changes', 'valid', 'skipped', 'error'], +}) + +export const FrontendFrameworkEnum = enumType({ + name: 'FrontendFrameworkEnum', + members: FRONTEND_FRAMEWORKS.map((t) => t.type), +}) + +export const FrontendFrameworkCategoryEnum = enumType({ + name: 'FrontendFrameworkCategoryEnum', + members: FRONTEND_FRAMEWORKS.map((t) => t.category), +}) + +export const CodeLanguageEnum = enumType({ + name: 'CodeLanguageEnum', + members: CODE_LANGUAGES.map((t) => t.type), +}) + +export const TestingTypeEnum = enumType({ + name: 'TestingTypeEnum', + members: ['e2e', 'component'], +}) diff --git a/packages/graphql/src/schemaTypes/enumTypes/index.ts b/packages/graphql/src/schemaTypes/enumTypes/index.ts new file mode 100644 index 0000000000..11a824f239 --- /dev/null +++ b/packages/graphql/src/schemaTypes/enumTypes/index.ts @@ -0,0 +1,11 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-BrowserFamilyEnum' +export * from './gql-BrowserStatus' +export * from './gql-CodeGenTypeEnum' +export * from './gql-ErrorTypeEnum' +export * from './gql-FileExtensionEnum' +export * from './gql-ProjectEnums' +export * from './gql-SpecEnum' +export * from './gql-WizardEnums' diff --git a/packages/graphql/src/schemaTypes/index.ts b/packages/graphql/src/schemaTypes/index.ts new file mode 100644 index 0000000000..9e2665df8b --- /dev/null +++ b/packages/graphql/src/schemaTypes/index.ts @@ -0,0 +1,9 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './enumTypes/' +export * from './inputTypes/' +export * from './interfaceTypes/' +export * from './objectTypes/' +export * from './scalarTypes/' +export * from './unions/' diff --git a/packages/graphql/src/schemaTypes/inputTypes/gql-FileDetailsInput.ts b/packages/graphql/src/schemaTypes/inputTypes/gql-FileDetailsInput.ts new file mode 100644 index 0000000000..78ba624ba3 --- /dev/null +++ b/packages/graphql/src/schemaTypes/inputTypes/gql-FileDetailsInput.ts @@ -0,0 +1,13 @@ +import { inputObjectType } from 'nexus' + +export const FileDetailsInput = inputObjectType({ + name: 'FileDetailsInput', + definition (t) { + t.nonNull.string('filePath', { + description: 'When we open a file we take a filePath, either relative to the project root, or absolute on disk', + }) + + t.int('column') + t.int('line') + }, +}) diff --git a/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts b/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts new file mode 100644 index 0000000000..ecf91c25c6 --- /dev/null +++ b/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts @@ -0,0 +1,19 @@ +import { inputObjectType } from 'nexus' +import { CodeLanguageEnum, FrontendFrameworkEnum, SupportedBundlerEnum } from '../enumTypes/gql-WizardEnums' + +export const WizardUpdateInput = inputObjectType({ + name: 'WizardUpdateInput', + definition (t) { + t.field('framework', { + type: FrontendFrameworkEnum, + }) + + t.field('bundler', { + type: SupportedBundlerEnum, + }) + + t.field('codeLanguage', { + type: CodeLanguageEnum, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/inputTypes/index.ts b/packages/graphql/src/schemaTypes/inputTypes/index.ts new file mode 100644 index 0000000000..176455db21 --- /dev/null +++ b/packages/graphql/src/schemaTypes/inputTypes/index.ts @@ -0,0 +1,5 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-FileDetailsInput' +export * from './gql-WizardUpdateInput' diff --git a/packages/graphql/src/schemaTypes/interfaceTypes/gql-ProjectLike.ts b/packages/graphql/src/schemaTypes/interfaceTypes/gql-ProjectLike.ts new file mode 100644 index 0000000000..47093225f6 --- /dev/null +++ b/packages/graphql/src/schemaTypes/interfaceTypes/gql-ProjectLike.ts @@ -0,0 +1,32 @@ +import { interfaceType } from 'nexus' + +export interface ProjectShape { + projectId?: string | null + projectRoot: string +} + +export const ProjectLike = interfaceType({ + name: 'ProjectLike', + description: 'Common base fields inherited by GlobalProject / CurrentProject', + definition (t) { + t.nonNull.string('projectRoot', { + description: 'Absolute path to the project on the filesystem', + }) + + t.string('projectId', { + description: 'Used to associate project with Cypress dashboard', + resolve: (source, args, ctx) => ctx.project.projectId().then((val) => val ?? null, () => null), + }) + + t.nonNull.string('title', { + resolve: (source, args, ctx) => ctx.project.projectTitle(source.projectRoot), + }) + }, + resolveType (root) { + return 'GlobalProject' + }, + sourceType: { + module: __dirname, + export: 'ProjectShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/interfaceTypes/index.ts b/packages/graphql/src/schemaTypes/interfaceTypes/index.ts new file mode 100644 index 0000000000..e704b30161 --- /dev/null +++ b/packages/graphql/src/schemaTypes/interfaceTypes/index.ts @@ -0,0 +1,4 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-ProjectLike' diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-AuthState.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-AuthState.ts new file mode 100644 index 0000000000..6dcc86f383 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-AuthState.ts @@ -0,0 +1,26 @@ +import { enumType, objectType } from 'nexus' +import { authStateName } from '@packages/types' + +export const AuthStateNameEnum = enumType({ + name: 'AuthStateNameEnum', + members: authStateName, +}) + +export const AuthState = objectType({ + name: 'AuthState', + description: 'Represents state of auth based on most recent message from login flow', + definition (t) { + t.field('name', { + type: AuthStateNameEnum, + description: 'Name of auth state, e.g. AUTH_BROWSER_LAUNCHED', + }) + + t.string('message', { + description: 'Message for the auth state', + }) + + t.nonNull.boolean('browserOpened', { + description: 'Whether the browser was successfully opened for login', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Browser.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Browser.ts new file mode 100644 index 0000000000..160d4c7b34 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Browser.ts @@ -0,0 +1,40 @@ +import { objectType } from 'nexus' +import { BrowserFamilyEnum } from '../enumTypes/gql-BrowserFamilyEnum' + +export const Browser = objectType({ + name: 'Browser', + description: 'Container representing a browser', + node: (obj, args, ctx) => ctx.browser.idForBrowser(obj), + definition (t) { + t.nonNull.string('channel') + t.nonNull.boolean('disabled', { + resolve: () => false, + }) + + t.nonNull.boolean('isSelected', { + resolve: (source, args, ctx) => ctx.browser.isSelected(source), + }) + + t.nonNull.string('displayName') + t.nonNull.field('family', { + type: BrowserFamilyEnum, + }) + + t.string('majorVersion') + t.nonNull.string('name') + t.nonNull.string('path') + t.nonNull.string('version') + t.string('warning') + t.nonNull.boolean('isFocusSupported', { + resolve: (source, args, ctx) => ctx.browser.isFocusSupported(source), + }) + + t.nonNull.boolean('isVersionSupported', { + resolve: (source, args, ctx) => ctx.browser.isVersionSupported(source), + }) + }, + sourceType: { + module: '@packages/types', + export: 'FoundBrowser', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-CachedUser.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-CachedUser.ts new file mode 100644 index 0000000000..a0d2aa3b08 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-CachedUser.ts @@ -0,0 +1,25 @@ +import dedent from 'dedent' +import { objectType } from 'nexus' + +export const CachedUser = objectType({ + name: 'CachedUser', + description: dedent` + When we don't have an immediate response for the cloudViewer request, we'll use this as a fallback to + render the avatar in the header bar / signal authenticated state immediately + `, + node: 'email', + definition (t) { + t.string('fullName', { + description: 'Name of the cached user', + resolve: (source) => source.name ?? null, + }) + + t.string('email', { + description: 'Email address of the cached user', + }) + }, + sourceType: { + export: 'AuthenticatedUserShape', + module: '@packages/data-context/src/data/coreDataShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-CodeFrame.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-CodeFrame.ts new file mode 100644 index 0000000000..96565c2329 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-CodeFrame.ts @@ -0,0 +1,31 @@ +import { objectType } from 'nexus' +import { FileParts } from './gql-FileParts' + +export const CodeFrame = objectType({ + name: 'CodeFrame', + description: 'A code frame to display for a file, used when displaying code related to errors', + definition (t) { + t.int('line', { + description: 'The line number of the code snippet to display', + }) + + t.int('column', { + description: 'The column of the error to display', + }) + + t.string('codeBlock', { + description: 'Source of the code frame to display', + }) + + t.nonNull.field('file', { + type: FileParts, + resolve (source, args, ctx) { + return { absolute: source.absolute } + }, + }) + }, + sourceType: { + module: '@packages/data-context/src/sources/ErrorDataSource', + export: 'CodeFrameShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-CodeGenGlobs.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-CodeGenGlobs.ts new file mode 100644 index 0000000000..135e21d8c6 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-CodeGenGlobs.ts @@ -0,0 +1,10 @@ +import { objectType } from 'nexus' + +export const CodeGenGlobs = objectType({ + name: 'CodeGenGlobs', + description: 'Glob patterns for detecting files for code gen.', + node: 'component', + definition (t) { + t.nonNull.string('component') + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-CurrentProject.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-CurrentProject.ts new file mode 100644 index 0000000000..160fe911db --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-CurrentProject.ts @@ -0,0 +1,220 @@ +import { PACKAGE_MANAGERS } from '@packages/types' +import { enumType, nonNull, objectType, stringArg } from 'nexus' +import path from 'path' +import { BrowserStatusEnum, FileExtensionEnum } from '..' +import { cloudProjectBySlug } from '../../stitching/remoteGraphQLCalls' +import { TestingTypeEnum } from '../enumTypes/gql-WizardEnums' +import { Browser } from './gql-Browser' +import { CodeGenGlobs } from './gql-CodeGenGlobs' +import { FileParts } from './gql-FileParts' +import { ProjectPreferences } from './gql-ProjectPreferences' +import { Spec } from './gql-Spec' + +export const PackageManagerEnum = enumType({ + name: 'PackageManagerEnum', + members: PACKAGE_MANAGERS, +}) + +export const CurrentProject = objectType({ + name: 'CurrentProject', + description: 'The currently opened Cypress project, represented by a cypress.config.{ts|js} file', + node: 'projectRoot', + definition (t) { + t.implements('ProjectLike') + + t.nonNull.field('packageManager', { + type: PackageManagerEnum, + resolve: (source, args, ctx) => ctx.coreData.packageManager, + }) + + t.boolean('isLoadingConfigFile', { + description: 'Whether we are currently loading the configFile', + }) + + t.boolean('isLoadingNodeEvents', { + description: 'Whether we are currently loading the setupNodeEvents', + }) + + t.field('currentTestingType', { + description: 'The mode the interactive runner was launched in', + type: TestingTypeEnum, + resolve: (_, args, ctx) => ctx.coreData.currentTestingType, + }) + + t.field('activeBrowser', { + type: Browser, + description: 'The currently selected browser for the project', + resolve: (source, args, ctx) => { + return ctx.coreData.activeBrowser + }, + }) + + t.list.nonNull.field('browsers', { + type: Browser, + description: 'Browsers found that are compatible with Cypress', + }) + + t.field('cloudProject', { + type: 'CloudProjectResult', + description: 'The remote associated project from Cypress Dashboard', + resolve: async (source, args, ctx, info) => { + const projectId = await ctx.project.projectId() + + if (!projectId) { + return null + } + + return cloudProjectBySlug(projectId, ctx, info) + }, + }) + + t.string('projectId', { + description: 'Used to associate project with Cypress dashboard', + resolve: (source, args, ctx) => ctx.project.projectId(), + }) + + t.boolean('isCTConfigured', { + description: 'Whether the user configured this project to use Component Testing', + resolve: (source, args, ctx) => { + // If the forceReconfigureProject for component is set, we want to notify + // the client side that the wizard has to start from the beginning + if (ctx.coreData.forceReconfigureProject?.component) { + return false + } + + return ctx.lifecycleManager.isTestingTypeConfigured('component') + }, + }) + + t.boolean('isE2EConfigured', { + description: 'Whether the user configured this project to use e2e Testing', + resolve: (source, args, ctx) => { + // If the forceReconfigureProject for e2e is set, we want to notify + // the client side that the wizard has to start from the beginning + if (ctx.coreData.forceReconfigureProject?.e2e) { + return false + } + + return ctx.lifecycleManager.isTestingTypeConfigured('e2e') + }, + }) + + t.boolean('needsLegacyConfigMigration', { + description: 'Whether the project needs to be migrated before proceeding', + resolve (source, args, ctx) { + return ctx.lifecycleManager.needsCypressJsonMigration() + }, + }) + + t.boolean('hasValidConfigFile', { + description: 'Whether the project has a valid config file', + resolve (source, args, ctx) { + return ctx.lifecycleManager.metaState.hasValidConfigFile + }, + }) + + t.boolean('hasTypescript', { + description: 'Whether the project has Typescript', + resolve (source, args, ctx) { + return ctx.lifecycleManager.metaState.hasTypescript + }, + }) + + t.field('fileExtensionToUse', { + type: FileExtensionEnum, + description: 'File extension to use based on if the project has typescript or not', + resolve: (source, args, ctx) => { + return ctx.lifecycleManager.fileExtensionToUse + }, + }) + + t.string('defaultSpecFileName', { + description: 'Default spec file name for spec creation', + resolve: (source, args, ctx) => { + return ctx.project.defaultSpecFileName() + }, + }) + + t.nonNull.list.nonNull.field('specs', { + description: 'A list of specs for the currently open testing type of a project', + type: Spec, + resolve: (source, args, ctx) => { + return ctx.project.specs + }, + }) + + t.nonNull.json('config', { + description: 'Project configuration', + resolve: (source, args, ctx) => { + return ctx.project.getResolvedConfigFields() + }, + }) + + t.json('savedState', { + description: 'Project saved state', + resolve: (source, args, ctx) => { + return ctx.project.getCurrentProjectSavedState() + }, + }) + + t.string('configFile', { + description: 'Config File, specified by the CLI or ', + resolve: (source, args, ctx) => { + return ctx.lifecycleManager.configFile.toString() + }, + }) + + t.string('configFileAbsolutePath', { + description: 'Config File Absolute Path', + resolve: async (source, args, ctx) => { + return ctx.lifecycleManager.configFilePath + }, + }) + + t.field('preferences', { + type: ProjectPreferences, + description: 'Cached preferences for this project', + resolve: (source, args, ctx) => { + return ctx.project.getProjectPreferences(path.basename(source.projectRoot)) + }, + }) + + t.nonNull.field('codeGenGlobs', { + type: CodeGenGlobs, + resolve: (src, args, ctx) => ctx.project.getCodeGenGlobs(), + }) + + t.list.field('codeGenCandidates', { + type: FileParts, + description: 'List of all code generation candidates stories', + args: { + glob: nonNull(stringArg()), + }, + resolve: (source, args, ctx) => { + return ctx.project.getCodeGenCandidates(args.glob) + }, + }) + + t.string('branch', { + description: 'The current branch of the project', + resolve: async (source, args, ctx) => { + return source.git?.currentBranch ?? null + }, + }) + + t.nonNull.boolean('isDefaultSpecPattern', { + description: 'True if the project is using the default spec pattern', + resolve: async (source, args, ctx) => ctx.project.getIsDefaultSpecPattern(), + }) + + t.nonNull.field('browserStatus', { + type: BrowserStatusEnum, + description: 'If the browser is open or not', + resolve: (source, args, ctx) => ctx.coreData.app.browserStatus, + }) + }, + sourceType: { + module: '@packages/data-context/src/data/ProjectLifecycleManager', + export: 'ProjectLifecycleManager', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-DevState.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-DevState.ts new file mode 100644 index 0000000000..0a2e6e140b --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-DevState.ts @@ -0,0 +1,45 @@ +import _ from 'lodash' +import { objectType } from 'nexus' + +const toExpand = new Set(['ProjectLifecycleManager']) + +export const DevState = objectType({ + name: 'DevState', + description: 'State associated/helpful for local development of Cypress', + definition (t) { + t.json('state', { + description: 'For debugging, the current application state', + resolve: (source, args, ctx) => { + function replacer (key: string, val: unknown) { + if (val && !Array.isArray(val) && _.isObject(val) && !_.isPlainObject(val)) { + if (toExpand.has(val.constructor.name)) { + return val + } + + return `[${val.constructor.name}]` + } + + return val + } + + return { + coreData: JSON.parse(JSON.stringify(ctx.coreData, replacer)), + modeOptions: ctx.modeOptions, + lifecycleManager: JSON.parse(JSON.stringify(ctx.lifecycleManager, replacer)), + } + }, + }) + + t.boolean('needsRelaunch', { + description: 'When we have edited server related files, we may want to relaunch the client.', + resolve (source, args, ctx) { + return Boolean(source.refreshState) + }, + }) + }, + + sourceType: { + module: '@packages/data-context/src/data/coreDataShape', + export: 'DevStateShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Editor.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Editor.ts new file mode 100644 index 0000000000..77b7fde49a --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Editor.ts @@ -0,0 +1,17 @@ +import { objectType } from 'nexus' + +export const Editor = objectType({ + name: 'Editor', + description: 'Represents an editor on the local machine', + definition (t) { + t.nonNull.string('id') + + t.nonNull.string('name', { + description: 'name of editor', + }) + + t.string('binary', { + description: 'Binary that opens the editor', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-ErrorWrapper.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-ErrorWrapper.ts new file mode 100644 index 0000000000..24f87cc2ea --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-ErrorWrapper.ts @@ -0,0 +1,63 @@ +import { stripAnsi } from '@packages/errors' +import { objectType } from 'nexus' + +import { ErrorTypeEnum } from '../enumTypes/gql-ErrorTypeEnum' +import { CodeFrame } from './gql-CodeFrame' + +export const ErrorWrapper = objectType({ + name: 'ErrorWrapper', + description: 'Base error', + definition (t) { + t.string('title', { + description: 'Optional title of the error. Used to optionally display a title above the error', + }) + + t.nonNull.string('errorName', { + description: 'Name of the error class', + resolve (source) { + return source.cypressError.originalError?.name || source.cypressError.name + }, + }) + + t.nonNull.string('errorStack', { + description: 'The error stack of either the original error from the user or from where the internal Cypress error was created', + resolve (source) { + return stripAnsi(source.cypressError.stack || '') + }, + }) + + t.nonNull.field('errorType', { + type: ErrorTypeEnum, + resolve: (source) => source.cypressError.type ?? 'UNEXPECTED_INTERNAL_ERROR', + }) + + t.nonNull.string('errorMessage', { + description: 'The markdown formatted content associated with the ErrorTypeEnum', + resolve (source) { + return source.cypressError.messageMarkdown ?? source.cypressError.message + }, + }) + + t.nonNull.boolean('isUserCodeError', { + description: 'Whether the error came from user code, can be used to determine whether to open a stack trace by default', + resolve (source, args, ctx) { + return ctx.error.isUserCodeError(source) + }, + }) + + t.field('codeFrame', { + type: CodeFrame, + description: 'The code frame to display in relation to the error', + resolve: (source, args, ctx) => { + return ctx.error.codeFrame(source).catch( + // Don't worry if we try to get a non-existent file + () => null, + ) + }, + }) + }, + sourceType: { + module: '@packages/errors', + export: 'ErrorWrapperSource', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-FileParts.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-FileParts.ts new file mode 100644 index 0000000000..8704b824eb --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-FileParts.ts @@ -0,0 +1,76 @@ +import { objectType } from 'nexus' +import path from 'path' + +export interface FilePartsShape { + line?: number + column?: number + absolute: string + // For when we're merging / creating the file and might not have the file contents on-disk yet + // used in the scaffolding + contents?: string +} + +export const FileParts = objectType({ + name: 'FileParts', + description: 'Represents a file on the file system', + node: 'absolute', + definition (t) { + t.nonNull.string('absolute', { + description: 'Absolute path to file (e.g. /Users/jess/my-project/src/component/MySpec.test.tsx)', + }) + + t.nonNull.string('relative', { + description: 'Relative path to file (e.g. src/component/MySpec.test.tsx)', + resolve (root, args, ctx) { + return path.relative(ctx.currentProject || '', root.absolute) + }, + }) + + t.nonNull.string('baseName', { + description: 'Full name of the file (e.g. MySpec.test.tsx)', + resolve (root, args, ctx) { + return path.basename(root.absolute) + }, + }) + + t.nonNull.string('name', { + description: 'Full name of spec file (e.g. MySpec.test.tsx)', + resolve (root) { + return path.basename(root.absolute) + }, + }) + + t.nonNull.string('fileExtension', { + description: `The file's extension`, + resolve (root) { + return path.extname(root.absolute) + }, + }) + + t.nonNull.string('fileName', { + description: `The first part of the file, without extensions (e.g. MySpec)`, + resolve (root) { + return path.basename(root.absolute).split('.')[0] ?? '' + }, + }) + + t.nonNull.string('contents', { + description: `The contents of the file`, + resolve (root, args, ctx) { + return root.contents || ctx.fs.readFile(root.absolute, 'utf8') + }, + }) + + t.int('line', { + description: 'If provided, used to specify the line of the file to open in openFileInIDE', + }) + + t.int('column', { + description: 'If provided, used to specify the column of the file to open in openFileInIDE', + }) + }, + sourceType: { + module: __filename, + export: 'FilePartsShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-GenerateSpecResponse.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-GenerateSpecResponse.ts new file mode 100644 index 0000000000..b46a413913 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-GenerateSpecResponse.ts @@ -0,0 +1,38 @@ +import { objectType } from 'nexus' +import { GeneratedSpecResult } from '../unions' +import { CurrentProject } from './gql-CurrentProject' +import type { FilePartsShape } from './gql-FileParts' + +export type ScaffoldedFileSource = { + status: 'changes' | 'valid' | 'skipped' | 'error' + description: string + file: FilePartsShape +} | { fileName: string, erroredCodegenCandidate: string } + +export const GenerateSpecResponse = objectType({ + name: 'GenerateSpecResponse', + description: 'Error from generated spec', + definition (t) { + t.field('currentProject', { + type: CurrentProject, + description: 'The currently opened project', + resolve: (root, args, ctx) => { + if (ctx.coreData.currentProject) { + return ctx.lifecycleManager + } + + return null + }, + }) + + t.field('generatedSpecResult', { + type: GeneratedSpecResult, + description: 'The file that have just been scaffolded or the fileName that errored', + resolve: (root, args, ctx) => root, + }) + }, + sourceType: { + module: __filename, + export: 'ScaffoldedFileSource', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-GeneratedSpecError.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-GeneratedSpecError.ts new file mode 100644 index 0000000000..3f7043b0d6 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-GeneratedSpecError.ts @@ -0,0 +1,10 @@ +import { objectType } from 'nexus' + +export const GeneratedSpecError = objectType({ + name: 'GeneratedSpecError', + description: 'Error from generated spec', + definition (t) { + t.nonNull.string('fileName') + t.nonNull.string('erroredCodegenCandidate') + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-GitInfo.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-GitInfo.ts new file mode 100644 index 0000000000..34a8577f2a --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-GitInfo.ts @@ -0,0 +1,30 @@ +import { objectType, enumType } from 'nexus' +import { gitStatusType } from '@packages/types' + +export const GitInfoStatusTypeEnum = enumType({ + name: 'GitInfoStatusType', + members: gitStatusType, +}) + +export const GitInfo = objectType({ + name: 'GitInfo', + description: 'Git information about a spec file', + definition (t) { + t.string('author', { + description: 'Last person to change the file in git', + }) + + t.string('lastModifiedTimestamp', { + description: 'last modified timestamp, eg 2021-09-14 13:43:19 +1000', + }) + + t.string('lastModifiedHumanReadable', { + description: 'last modified as a pretty string, eg 2 days ago', + }) + + t.field('statusType', { + type: GitInfoStatusTypeEnum, + description: 'status type - created or modified', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-GlobalProject.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-GlobalProject.ts new file mode 100644 index 0000000000..d6c30326eb --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-GlobalProject.ts @@ -0,0 +1,10 @@ +import { objectType } from 'nexus' + +export const GlobalProject = objectType({ + name: 'GlobalProject', + description: 'A project which exists on the filesystem but has not been opened', + node: 'projectRoot', + definition (t) { + t.implements('ProjectLike') + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-LocalSettings.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-LocalSettings.ts new file mode 100644 index 0000000000..bc560ecab1 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-LocalSettings.ts @@ -0,0 +1,36 @@ +import { objectType } from 'nexus' +import { Editor } from './gql-Editor' + +export const LocalSettingsPreferences = objectType({ + name: 'LocalSettingsPreferences', + description: 'local setting preferences', + definition (t) { + t.boolean('autoScrollingEnabled') + t.string('preferredEditorBinary') + t.boolean('isSpecsListOpen') + t.int('reporterWidth') + t.int('specListWidth') + t.boolean('isSideNavigationOpen') + t.string('proxyServer', { + resolve: (source, args, ctx) => ctx.env.HTTP_PROXY ?? null, + }) + + t.string('proxyBypass', { + resolve: (source, args, ctx) => ctx.env.NO_PROXY ?? null, + }) + }, +}) + +export const LocalSettings = objectType({ + name: 'LocalSettings', + description: 'local settings on a device-by-device basis', + definition (t) { + t.nonNull.list.nonNull.field('availableEditors', { + type: Editor, + }) + + t.nonNull.field('preferences', { + type: LocalSettingsPreferences, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Migration.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Migration.ts new file mode 100644 index 0000000000..fb01b2a72c --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Migration.ts @@ -0,0 +1,283 @@ +import { enumType, objectType } from 'nexus' +import { TestingTypeEnum } from '..' +import { MIGRATION_STEPS } from '@packages/types' + +export const MigrationStepEnum = enumType({ + name: 'MigrationStepEnum', + members: MIGRATION_STEPS, +}) + +export const MigrationStep = objectType({ + name: 'MigrationStep', + node: 'name', + description: 'Contains all data related to the 9.X to 10.0 migration UI', + definition (t) { + t.nonNull.field('name', { + type: MigrationStepEnum, + description: 'Identifier of the step', + }) + + t.nonNull.boolean('isCurrentStep', { + description: 'This is the current step', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.step === source.name + }, + }) + + t.nonNull.boolean('isCompleted', { + description: 'Has the current step been completed', + resolve: (source, args, ctx) => { + const indexOfObservedStep = ctx.coreData.migration.filteredSteps.indexOf(source.name) + const indexOfCurrentStep = ctx.coreData.migration.filteredSteps.indexOf(ctx.coreData.migration.step) + + return indexOfObservedStep < indexOfCurrentStep + }, + }) + + t.nonNull.int('index', { + description: 'Index of the step in the list', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.filteredSteps.indexOf(source.name) + 1 + }, + }) + }, +}) + +export const MigrationFilePart = objectType({ + name: 'MigrationFilePart', + node: (obj) => obj.text, + definition (t) { + t.nonNull.string('text', { + description: 'part of filename', + }) + + t.nonNull.boolean('highlight', { + description: 'should highlight in migration UI', + }) + + t.string('group', { + description: 'is this part a folder or extension that needs migration', + }) + }, +}) + +export const ManualMigrationFile = objectType({ + name: 'ManualMigrationFile', + node: 'relative', + definition (t) { + t.nonNull.boolean('moved', { + description: 'has the file been moved since opening the migration helper', + }) + + t.nonNull.string('relative', { + description: 'name of file to migrate', + }) + }, +}) + +export const ManualMigration = objectType({ + name: 'ManualMigration', + node: ({ files }) => files.map((f) => f.relative).join(), + definition (t) { + t.nonNull.list.nonNull.field('files', { + type: ManualMigrationFile, + description: 'files needing manual migration', + }) + + t.nonNull.boolean('completed', { + description: 'is the manual migration completed (all files are moved)', + }) + }, +}) + +export const MigrationFileData = objectType({ + name: 'MigrationFileData', + node: (obj) => obj.parts.map((file) => file.text).join(''), + definition (t) { + t.nonNull.string('relative') + + t.nonNull.list.nonNull.field('parts', { + type: MigrationFilePart, + }) + }, +}) + +export const MigrationFile = objectType({ + name: 'MigrationFile', + definition (t) { + t.nonNull.field('testingType', { + type: TestingTypeEnum, + }) + + t.nonNull.field('before', { + type: MigrationFileData, + }) + + t.nonNull.field('after', { + type: MigrationFileData, + }) + }, +}) + +export const MigrationRegexp = objectType({ + name: 'MigrationRegexp', + definition (t) { + t.nonNull.string('beforeE2E', { + description: 'regexp to identify existing specs in e2e', + }) + + t.nonNull.string('afterE2E', { + description: 'regexp to use to rename existing specs in e2e', + }) + + t.nonNull.string('beforeComponent', { + description: 'regexp to identify existing specs in component', + }) + + t.nonNull.string('afterComponent', { + description: 'regexp to use to rename existing specs in component', + }) + }, +}) + +export const Migration = objectType({ + name: 'Migration', + description: 'Contains all data related to the 9.X to 10.0 migration UI', + definition (t) { + t.nonNull.list.nonNull.field('filteredSteps', { + type: MigrationStep, + description: 'Steps filtered with the current context', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.filteredSteps.map((name) => { + return { + name, + } + }) + }, + }) + + t.nonNull.list.nonNull.field('specFiles', { + description: 'All spec files after conversion', + type: MigrationFile, + resolve: async (source, args, ctx) => { + const result = await ctx.migration.getSpecsForMigrationGuide() + + return result + }, + }) + + t.field('manualFiles', { + description: 'List of files needing manual conversion', + type: ManualMigration, + resolve: async (source, args, ctx) => { + // avoid starting the watcher when not on this step + if (ctx.coreData.migration.step !== 'renameManual') { + return null + } + + const status = await ctx.migration.getComponentTestingMigrationStatus() + + if (!status) { + return null + } + + return { + completed: status.completed, + // we sort it to make sure the endpoint always returns the + // specs in the same order, so things don't jump around. + files: [...status.files.values()] + .sort((x, y) => y.relative.length - x.relative.length), + } + }, + }) + + t.field('supportFiles', { + description: 'Support files needing automated rename', + type: MigrationFile, + resolve: (source, args, ctx) => { + return ctx.migration.supportFilesForMigrationGuide() + }, + }) + + t.nonNull.string('configFileNameBefore', { + description: 'the name of the config file to be migrated', + resolve: (source, args, ctx) => { + return ctx.lifecycleManager.legacyConfigFile + }, + }) + + t.nonNull.string('configFileNameAfter', { + description: 'the name of the config file after the migration', + resolve: (source, args, ctx) => { + return ctx.migration.configFileNameAfterMigration + }, + }) + + t.nonNull.string('configBeforeCode', { + description: 'contents of the cypress.json file before conversion', + resolve: (source, args, ctx) => { + return JSON.stringify(ctx.coreData.migration.legacyConfigForMigration, null, 2) + }, + }) + + t.nonNull.string('configAfterCode', { + description: 'contents of the cypress.json file after conversion', + resolve: (source, args, ctx) => { + return ctx.migration.createConfigString() + }, + }) + + t.nonNull.string('integrationFolder', { + description: 'the integration folder path used to store e2e tests', + resolve: async (source, args, ctx) => (await ctx.migration.integrationFolder()).toString(), + }) + + t.nonNull.string('componentFolder', { + description: 'the component folder path used to store components tests', + resolve: async (source, args, ctx) => (await ctx.migration.componentFolder()).toString(), + }) + + t.nonNull.boolean('hasCustomIntegrationFolder', { + description: 'whether the integration folder is custom or not', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.flags.hasCustomIntegrationFolder + } + , + }) + + t.nonNull.boolean('hasCustomIntegrationTestFiles', { + description: 'whether the testFiles member is custom or not in integration', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.flags.hasCustomIntegrationTestFiles + }, + }) + + t.nonNull.boolean('hasCustomComponentFolder', { + description: 'whether the component folder is custom or not', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.flags.hasCustomComponentFolder + }, + }) + + t.nonNull.boolean('hasCustomComponentTestFiles', { + description: 'whether the testFiles member is custom or not in component testing', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.flags.hasCustomComponentTestFiles + }, + }) + + t.nonNull.boolean('hasComponentTesting', { + description: 'whether component testing is set up in the migrated config or not', + resolve: (source, args, ctx) => { + return ctx.coreData.migration.flags.hasComponentTesting + }, + }) + + t.boolean('hasTypescript', { + description: 'Whether the project has Typescript', + resolve (source, args, ctx) { + return ctx.lifecycleManager.metaState.hasTypescript + }, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts new file mode 100644 index 0000000000..214cec3549 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts @@ -0,0 +1,656 @@ +import { arg, booleanArg, enumType, idArg, mutationType, nonNull, stringArg, list } from 'nexus' +import { Wizard } from './gql-Wizard' +import { CodeGenTypeEnum } from '../enumTypes/gql-CodeGenTypeEnum' +import { TestingTypeEnum } from '../enumTypes/gql-WizardEnums' +import { FileDetailsInput } from '../inputTypes/gql-FileDetailsInput' +import { WizardUpdateInput } from '../inputTypes/gql-WizardUpdateInput' +import { CurrentProject } from './gql-CurrentProject' +import { GenerateSpecResponse } from './gql-GenerateSpecResponse' +import { Query } from './gql-Query' +import { ScaffoldedFile } from './gql-ScaffoldedFile' + +export const mutation = mutationType({ + definition (t) { + t.field('copyTextToClipboard', { + type: 'Boolean', + description: 'add the passed text to the local clipboard', + args: { + text: nonNull(stringArg()), + }, + resolve: (_, { text }, ctx) => { + ctx.electronApi.copyTextToClipboard(text) + + return true + }, + }) + + t.field('resetErrorsAndLoadConfig', { + type: Query, + description: 'Resets errors and attempts to reload the config', + resolve: async (_, args, ctx) => { + ctx.update((d) => { + d.baseError = null + d.warnings = [] + }) + + // Wait for the project config to be reloaded + await ctx.lifecycleManager.refreshLifecycle() + + return {} + }, + }) + + t.field('devRelaunch', { + type: 'Boolean', + description: 'Development only: Triggers or dismisses a prompted refresh by touching the file watched by our development scripts', + args: { + action: nonNull(enumType({ + name: 'DevRelaunchAction', + members: ['trigger', 'dismiss'], + }).asArg()), + }, + resolve: async (_, args, ctx) => { + if (args.action === 'trigger') { + await ctx.actions.dev.triggerRelaunch() + } else { + ctx.actions.dev.dismissRelaunch() + } + + return true + }, + }) + + t.nonNull.boolean('matchesSpecPattern', { + description: 'Check if a give spec file will match the project spec pattern', + args: { + specFile: nonNull(stringArg()), + }, + resolve: (source, args, ctx) => { + if (!ctx.currentProject) { + return false + } + + return ctx.project.matchesSpecPattern(args.specFile) + }, + }) + + t.field('internal_clearLatestProjectCache', { + type: 'Boolean', + resolve: async (_, args, ctx) => { + await ctx.actions.project.clearLatestProjectCache() + + return true + }, + }) + + t.field('openExternal', { + type: 'Boolean', + args: { + url: nonNull(stringArg()), + includeGraphqlPort: booleanArg(), + }, + resolve: (_, args, ctx) => { + let url = args.url + + if (args.includeGraphqlPort && process.env.CYPRESS_INTERNAL_GRAPHQL_PORT) { + url = `${args.url}?port=${process.env.CYPRESS_INTERNAL_GRAPHQL_PORT}` + } + + ctx.actions.electron.openExternal(url) + + return true + }, + }) + + t.field('internal_clearProjectPreferencesCache', { + type: 'Boolean', + args: { + projectTitle: nonNull(stringArg()), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.project.clearProjectPreferencesCache(args.projectTitle) + + return true + }, + }) + + t.field('internal_clearAllProjectPreferencesCache', { + type: 'Boolean', + resolve: async (_, args, ctx) => { + await ctx.actions.project.clearAllProjectPreferencesCache() + + return true + }, + }) + + t.field('scaffoldTestingType', { + type: 'Query', + resolve: async (_, args, ctx) => { + await ctx.actions.wizard.scaffoldTestingType() + + return {} + }, + }) + + t.field('completeSetup', { + type: 'Query', + resolve: async (_, args, ctx) => { + await ctx.actions.wizard.completeSetup() + + return {} + }, + }) + + t.field('clearCurrentProject', { + type: 'Query', + description: 'Clears the currently active project', + resolve: async (_, args, ctx) => { + await ctx.actions.project.clearCurrentProject() + ctx.actions.wizard.resetWizard() + + return {} + }, + }) + + t.field('clearCurrentTestingType', { + type: 'Query', + resolve: async (_, args, ctx) => { + ctx.lifecycleManager.setAndLoadCurrentTestingType(null) + + return {} + }, + }) + + t.field('setAndLoadCurrentTestingType', { + type: 'Query', + args: { + testingType: nonNull(arg({ type: TestingTypeEnum })), + }, + resolve: async (source, args, ctx) => { + ctx.actions.project.setAndLoadCurrentTestingType(args.testingType) + + // if necessary init the wizard for configuration + if (ctx.coreData.currentTestingType + && !ctx.lifecycleManager.isTestingTypeConfigured(ctx.coreData.currentTestingType)) { + await ctx.actions.wizard.initialize() + + if (ctx.wizardData.chosenLanguage === 'ts') { + ctx.lifecycleManager.scaffoldFilesIfNecessary() + } + } + + return {} + }, + }) + + t.field('setPromptShown', { + type: 'Boolean', + description: 'Save the prompt-shown state for this project', + args: { slug: nonNull('String') }, + resolve: (_, args, ctx) => { + ctx.actions.project.setPromptShown(args.slug) + + return true + }, + }) + + t.field('wizardUpdate', { + type: Wizard, + description: 'Updates the different fields of the wizard data store', + args: { + input: nonNull(arg({ type: WizardUpdateInput })), + }, + resolve: async (source, args, ctx) => { + if (args.input.framework) { + ctx.actions.wizard.setFramework(args.input.framework) + } + + if (args.input.bundler) { + ctx.actions.wizard.setBundler(args.input.bundler) + } + + if (args.input.codeLanguage) { + ctx.actions.wizard.setCodeLanguage(args.input.codeLanguage) + } + + // TODO: remove when live-mutations are implements + // signal to launchpad to reload the data context + ctx.emitter.toLaunchpad() + + return ctx.wizardData + }, + }) + + t.field('launchpadSetBrowser', { + type: CurrentProject, + description: 'Sets the active browser', + args: { + id: nonNull(idArg({ + description: 'ID of the browser that we want to set', + })), + }, + async resolve (_, args, ctx) { + await ctx.actions.app.setActiveBrowserById(args.id) + + return ctx.lifecycleManager + }, + }) + + t.field('generateSpecFromSource', { + type: GenerateSpecResponse, + description: 'Generate spec from source', + args: { + codeGenCandidate: nonNull(stringArg()), + type: nonNull(CodeGenTypeEnum), + erroredCodegenCandidate: stringArg(), + }, + resolve: (_, args, ctx) => { + return ctx.actions.project.codeGenSpec(args.codeGenCandidate, args.type, args.erroredCodegenCandidate) + }, + }) + + t.nonNull.list.nonNull.field('scaffoldIntegration', { + type: ScaffoldedFile, + resolve: (src, args, ctx) => { + return ctx.actions.project.scaffoldIntegration() + }, + }) + + t.field('login', { + type: Query, + description: 'Auth with Cypress Dashboard', + resolve: async (_, args, ctx) => { + await ctx.actions.auth.login() + + return {} + }, + }) + + t.field('logout', { + type: Query, + description: 'Log out of Cypress Dashboard', + resolve: async (_, args, ctx) => { + await ctx.actions.auth.logout() + + return {} + }, + }) + + t.field('launchOpenProject', { + type: CurrentProject, + description: 'Launches project from open_project global singleton', + args: { + specPath: stringArg(), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.project.launchProject(ctx.coreData.currentTestingType, {}, args.specPath) + + return ctx.lifecycleManager + }, + }) + + t.field('addProject', { + type: Query, + description: 'Add project to projects array and cache it', + args: { + path: stringArg(), + open: booleanArg({ description: 'Whether to open the project when added' }), + }, + resolve: async (_, args, ctx) => { + ctx.actions.wizard.resetWizard() + let path = args.path + + if (!path) { + await ctx.actions.project.addProjectFromElectronNativeFolderSelect() + + return {} + } + + await ctx.actions.project.addProject({ + ...args, + path, + }) + + return {} + }, + }) + + t.field('removeProject', { + type: Query, + description: 'Remove project from projects array and cache', + args: { + path: nonNull(stringArg()), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.project.removeProject(args.path) + + return {} + }, + }) + + t.field('setCurrentProject', { + type: Query, + description: 'Set active project to run tests on', + args: { + path: nonNull(stringArg()), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.project.setCurrentProject(args.path) + + return {} + }, + }) + + t.nonNull.field('setProjectPreferences', { + type: Query, + description: 'Save the projects preferences to cache', + args: { + testingType: nonNull(TestingTypeEnum), + }, + async resolve (_, args, ctx) { + await ctx.actions.project.setProjectPreferences(args) + + return {} + }, + }) + + t.nonNull.field('resetAuthState', { + type: Query, + description: 'Reset the Auth State', + resolve (_, args, ctx) { + ctx.actions.auth.resetAuthState() + + return {} + }, + }) + + t.nonNull.field('resetWizard', { + type: 'Boolean', + description: 'Reset the Wizard to the starting position', + resolve: (_, args, ctx) => { + ctx.actions.wizard.resetWizard() + ctx.actions.electron.refreshBrowserWindow() + + return true + }, + }) + + t.nonNull.field('hideBrowserWindow', { + type: 'Boolean', + description: 'Hides the launchpad windows', + resolve: (_, args, ctx) => { + ctx.actions.electron.hideBrowserWindow() + + return true + }, + }) + + t.nonNull.field('resetLatestVersionTelemetry', { + type: 'Boolean', + description: 'Resets the latest version call to capture additional telemetry for the current user', + resolve: async (_, args, ctx) => { + ctx.actions.versions.resetLatestVersionTelemetry() + + return true + }, + }) + + t.nonNull.field('focusActiveBrowserWindow', { + type: 'Boolean', + description: 'Sets focus to the active browser window', + resolve: async (_, args, ctx) => { + await ctx.actions.browser.focusActiveBrowserWindow() + + return true + }, + }) + + t.nonNull.field('reconfigureProject', { + type: 'Boolean', + description: 'show the launchpad windows', + resolve: async (_, args, ctx) => { + ctx.actions.project.setForceReconfigureProjectByTestingType({ forceReconfigureProject: true }) + await ctx.actions.project.reconfigureProject() + + return true + }, + }) + + t.field('setPreferences', { + type: Query, + description: [ + 'Update local preferences (also known as appData).', + 'The payload, `value`, should be a `JSON.stringified()`', + 'object of the new values you\'d like to persist.', + 'Example: `setPreferences (value: JSON.stringify({ lastOpened: Date.now() }))`', + ].join(' '), + args: { + value: nonNull(stringArg()), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.localSettings.setPreferences(args.value) + + return {} + }, + }) + + t.field('openDirectoryInIDE', { + description: 'Open a path in preferred IDE', + type: 'Boolean', + args: { + path: nonNull(stringArg()), + }, + resolve: (_, args, ctx) => { + ctx.actions.project.openDirectoryInIDE(args.path) + + return true + }, + }) + + t.field('openInFinder', { + description: 'Open a path in the local file explorer', + type: 'Boolean', + args: { + path: nonNull(stringArg()), + }, + resolve: (_, args, ctx) => { + ctx.actions.electron.showItemInFolder(args.path) + + return true + }, + }) + + t.field('openFileInIDE', { + description: 'Open a file on specified line and column in preferred IDE', + type: 'Boolean', + args: { + input: nonNull(arg({ + type: FileDetailsInput, + })), + }, + resolve: (_, args, ctx) => { + ctx.actions.file.openFile( + args.input.filePath, + args.input.line || 1, + args.input.column || 1, + ) + + return true + }, + }) + + t.field('migrateRenameSpecs', { + description: 'While migrating to 10+ renames files to match the new .cy pattern', + type: Query, + args: { + skip: booleanArg(), + before: list(nonNull(stringArg({ + description: 'specs to move - current name', + }))), + after: list(nonNull(stringArg({ + description: 'specs to move - current name', + }))), + }, + resolve: async (_, { skip, before, after }, ctx) => { + if (!skip && before && after) { + await ctx.actions.migration.renameSpecFiles(before, after) + } + + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateRenameSpecsFolder', { + description: 'When the user decides to skip specs rename', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.renameSpecsFolder() + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateSkipManualRename', { + description: 'While migrating to 10+ skip manual rename step', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateCloseManualRenameWatcher', { + description: 'While migrating to 10+ skip manual rename step', + type: 'Boolean', + resolve: async (_, args, ctx) => { + await ctx.actions.migration.closeManualRenameWatcher() + + return true + }, + }) + + t.field('finishedRenamingComponentSpecs', { + description: 'user has finished migration component specs - move to next step', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateRenameSupport', { + description: 'While migrating to 10+ launch renaming of support file', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.renameSupportFile() + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateConfigFile', { + description: 'Transforms cypress.json file into cypress.config.js file', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.createConfigFile() + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('migrateComponentTesting', { + description: 'Merges the component testing config in cypress.config.{js,ts}', + type: Query, + resolve: async (_, args, ctx) => { + await ctx.actions.migration.nextStep() + + return {} + }, + }) + + t.field('setProjectIdInConfigFile', { + description: 'Set the projectId field in the config file of the current project', + type: Query, + args: { + projectId: nonNull(stringArg()), + }, + resolve: async (_, args, ctx) => { + await ctx.actions.project.setProjectIdInConfigFile(args.projectId) + + // Wait for the project config to be reloaded + await ctx.lifecycleManager.refreshLifecycle() + + return {} + }, + }) + + t.field('closeBrowser', { + description: 'Close active browser', + type: 'Boolean', + resolve: async (source, args, ctx) => { + await ctx.actions.browser.closeBrowser() + + return true + }, + }) + + t.field('switchTestingTypeAndRelaunch', { + description: 'Switch Testing type and relaunch browser', + type: 'Boolean', + args: { + testingType: nonNull(arg({ type: TestingTypeEnum })), + }, + resolve: async (source, args, ctx) => { + ctx.project.setRelaunchBrowser(true) + ctx.actions.project.setAndLoadCurrentTestingType(args.testingType) + await ctx.actions.project.reconfigureProject() + + return true + }, + }) + + t.field('setTestingTypeAndReconfigureProject', { + description: 'Set the selected testing type, and reconfigure the project', + type: Query, + args: { + testingType: nonNull(arg({ type: TestingTypeEnum })), + isApp: nonNull(booleanArg()), + }, + resolve: async (source, args, ctx) => { + ctx.actions.project.setForceReconfigureProjectByTestingType({ forceReconfigureProject: true, testingType: args.testingType }) + ctx.actions.project.setAndLoadCurrentTestingType(args.testingType) + + if (args.isApp) { + await ctx.actions.project.reconfigureProject() + } + + return {} + }, + }) + + t.field('dismissWarning', { + type: Query, + description: `Dismisses a warning displayed by the frontend`, + resolve: (source) => { + return {} + }, + }) + + t.field('pingBaseUrl', { + type: Query, + description: 'Ping configured Base URL', + resolve: async (source, args, ctx) => { + await ctx.actions.project.pingBaseUrl() + + return {} + }, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-ProjectPreferences.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-ProjectPreferences.ts new file mode 100644 index 0000000000..594fb64428 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-ProjectPreferences.ts @@ -0,0 +1,11 @@ +import { objectType } from 'nexus' + +export const ProjectPreferences = objectType({ + name: 'ProjectPreferences', + description: 'Preferences specific to a project', + definition (t) { + t.string('testingType', { + description: 'The preferred testing type to start in', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Query.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Query.ts new file mode 100644 index 0000000000..74ee1f752b --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Query.ts @@ -0,0 +1,114 @@ +import { objectType } from 'nexus' +import { ProjectLike, ScaffoldedFile } from '..' +import { CurrentProject } from './gql-CurrentProject' +import { DevState } from './gql-DevState' +import { AuthState } from './gql-AuthState' +import { LocalSettings } from './gql-LocalSettings' +import { Migration } from './gql-Migration' +import { VersionData } from './gql-VersionData' +import { Wizard } from './gql-Wizard' +import { ErrorWrapper } from './gql-ErrorWrapper' +import { CachedUser } from './gql-CachedUser' + +export const Query = objectType({ + name: 'Query', + description: 'The root "Query" type containing all entry fields for our querying', + definition (t) { + t.field('baseError', { + type: ErrorWrapper, + resolve: (root, args, ctx) => ctx.baseError, + }) + + t.field('cachedUser', { + type: CachedUser, + resolve: (root, args, ctx) => ctx.user, + }) + + t.nonNull.list.nonNull.field('warnings', { + type: ErrorWrapper, + description: 'A list of warnings', + resolve: (source, args, ctx) => { + return ctx.coreData.warnings + }, + }) + + t.nonNull.field('wizard', { + type: Wizard, + description: 'Metadata about the wizard', + resolve: (root, args, ctx) => ctx.coreData.wizard, + }) + + t.field('migration', { + type: Migration, + description: 'Metadata about the migration, null if we aren\'t showing it', + resolve: (root, args, ctx) => ctx.coreData.migration.legacyConfigForMigration ? ctx.coreData.migration : null, + }) + + t.nonNull.field('dev', { + type: DevState, + description: 'The state of any info related to local development of the runner', + resolve: (root, args, ctx) => ctx.coreData.dev, + }) + + t.field('versions', { + deferIfNotLoaded: true, + type: VersionData, + description: 'Previous versions of cypress and their release date', + resolve: (root, args, ctx) => { + return ctx.versions.versionData() + }, + }) + + t.field('currentProject', { + type: CurrentProject, + description: 'The currently opened project', + resolve: (root, args, ctx) => { + if (ctx.coreData.currentProject) { + return ctx.lifecycleManager + } + + return null + }, + }) + + t.nonNull.list.nonNull.field('projects', { + type: ProjectLike, + description: 'All known projects for the app', + resolve: (root, args, ctx) => ctx.appData.projects, + }) + + t.nonNull.boolean('isInGlobalMode', { + description: 'Whether the app is in global mode or not', + resolve: (source, args, ctx) => !ctx.currentProject, + }) + + t.nonNull.boolean('projectRootFromCI', { + description: 'Whether the project was specified from the --project flag', + resolve: (source, args, ctx) => Boolean(ctx.modeOptions.projectRoot), + }) + + t.nonNull.field('authState', { + type: AuthState, + description: 'The latest state of the auth process', + resolve: (source, args, ctx) => ctx.coreData.authState, + }) + + t.nonNull.field('localSettings', { + type: LocalSettings, + description: 'local settings on a device-by-device basis', + resolve: (source, args, ctx) => { + return ctx.coreData.localSettings + }, + }) + + t.list.nonNull.field('scaffoldedFiles', { + description: 'The files that have just been scaffolded', + type: ScaffoldedFile, + resolve: (_, args, ctx) => ctx.coreData.scaffoldedFiles, + }) + }, + sourceType: { + module: '@packages/graphql', + export: 'RemoteExecutionRoot', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-ScaffoldedFile.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-ScaffoldedFile.ts new file mode 100644 index 0000000000..cca38f872e --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-ScaffoldedFile.ts @@ -0,0 +1,23 @@ +import { objectType } from 'nexus' +import { FileParts } from './gql-FileParts' +import { WizardConfigFileStatusEnum } from '../enumTypes' + +export const ScaffoldedFile = objectType({ + name: 'ScaffoldedFile', + description: 'A file that we just added to the filesystem during project setup', + definition (t) { + t.nonNull.field('status', { + description: 'Info about the field', + type: WizardConfigFileStatusEnum, + }) + + t.nonNull.string('description', { + description: 'Info about the file we just scaffolded', + }) + + t.nonNull.field('file', { + type: FileParts, + description: 'Info about the file', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Spec.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Spec.ts new file mode 100644 index 0000000000..ef83db8923 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Spec.ts @@ -0,0 +1,51 @@ +import { objectType } from 'nexus' +import { SpecTypeEnum } from '../enumTypes' +import { GitInfo } from './gql-GitInfo' + +export const Spec = objectType({ + name: 'Spec', + description: 'Represents a spec on the file system', + node: 'absolute', + definition (t) { + t.nonNull.field('specType', { + type: SpecTypeEnum, + description: 'Type of spec (e.g. component | integration)', + }) + + t.nonNull.string('absolute', { + description: 'Absolute path to spec (e.g. /Users/jess/my-project/src/component/MySpec.test.tsx)', + }) + + t.nonNull.string('relative', { + description: 'Relative path to spec (e.g. src/component/MySpec.test.tsx)', + }) + + t.nonNull.string('baseName', { + description: 'Full name of spec file (e.g. MySpec.test.tsx)', + }) + + t.nonNull.string('name', { + description: 'Full name of spec file (e.g. MySpec.test.tsx)', + }) + + t.nonNull.string('fileExtension', { + description: 'The file extension (e.g. tsx, jsx)', + }) + + t.nonNull.string('specFileExtension', { + description: `The spec file's extension, including "spec" pattern (e.g. .spec.tsx, -spec.tsx, -test.tsx)`, + }) + + t.nonNull.string('fileName', { + description: `The first part of the file, without extensions (e.g. MySpec)`, + }) + + t.field('gitInfo', { + type: GitInfo, + description: 'Git information about the spec file', + resolve: async (source, args, ctx) => { + return ctx.lifecycleManager.git?.gitInfoFor(source.absolute) ?? null + }, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Subscription.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Subscription.ts new file mode 100644 index 0000000000..cb53a3c588 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Subscription.ts @@ -0,0 +1,69 @@ +import { list, subscriptionType } from 'nexus' +import { CurrentProject, DevState, Query } from '.' +import { Spec } from './gql-Spec' + +export const Subscription = subscriptionType({ + definition (t) { + t.field('authChange', { + type: Query, + description: 'Triggered when the auth state changes', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('authChange'), + resolve: (source, args, ctx) => ({}), + }) + + t.field('devChange', { + type: DevState, + description: 'Issued for internal development changes', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('devChange'), + resolve: (source, args, ctx) => ctx.coreData.dev, + }) + + t.field('cloudViewerChange', { + type: Query, + description: 'Triggered when there is a change to the info associated with the cloud project (org added, project added)', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('cloudViewerChange'), + resolve: (source, args, ctx) => { + return { + requestPolicy: 'network-only', + } as const + }, + }) + + t.field('browserStatusChange', { + type: CurrentProject, + description: 'Status of the currently opened browser', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('browserStatusChange'), + resolve: (source, args, ctx) => ctx.lifecycleManager, + }) + + t.field('specsChange', { + type: CurrentProject, + description: 'Issued when the watched specs for the project changes', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('specsChange'), + resolve: (source, args, ctx) => ctx.lifecycleManager, + }) + + t.field('gitInfoChange', { + type: list(Spec), + description: 'When the git info has refreshed for some or all of the specs, we fire this event with the specs updated', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('gitInfoChange'), + resolve: (absolutePaths: string[] | undefined, args, ctx) => { + // Send back the git info for all specs on subscribe + if (absolutePaths === undefined) { + return ctx.project.specs + } + + const pathsToSend = new Set(absolutePaths) + + return ctx.project.specs.filter((s) => pathsToSend.has(s.absolute)) + }, + }) + + t.field('branchChange', { + type: CurrentProject, + description: 'Issued when the current branch of a project changes', + subscribe: (source, args, ctx) => ctx.emitter.subscribeTo('branchChange'), + resolve: (source, args, ctx) => ctx.lifecycleManager, + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-TestingTypeInfo.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-TestingTypeInfo.ts new file mode 100644 index 0000000000..2325bb72f1 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-TestingTypeInfo.ts @@ -0,0 +1,15 @@ +import { objectType } from 'nexus' +import { TestingTypeEnum } from '../enumTypes/gql-WizardEnums' + +export const TestingTypeInfo = objectType({ + name: 'TestingTypeInfo', + node: 'type', + definition (t) { + t.nonNull.field('type', { + type: TestingTypeEnum, + }) + + t.nonNull.string('description') + t.nonNull.string('title') + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Version.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Version.ts new file mode 100644 index 0000000000..52d14612a5 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Version.ts @@ -0,0 +1,19 @@ +import { objectType } from 'nexus' + +export const Version = objectType({ + name: 'Version', + description: 'Version of Cypress and release date', + definition (t) { + t.nonNull.string('id', { + description: 'unique id', + }) + + t.nonNull.string('version', { + description: 'Version number (follows semantic versioning)', + }) + + t.nonNull.string('released', { + description: 'Release date as an iso8601 timestamp', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-VersionData.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-VersionData.ts new file mode 100644 index 0000000000..bd4b099998 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-VersionData.ts @@ -0,0 +1,18 @@ +import { objectType } from 'nexus' +import { Version } from './gql-Version' + +export const VersionData = objectType({ + name: 'VersionData', + description: 'Version of Cypress and release date', + definition (t) { + t.nonNull.field('latest', { + type: Version, + description: 'latest version of cypress', + }) + + t.nonNull.field('current', { + type: Version, + description: 'current version of cypress you are using', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts new file mode 100644 index 0000000000..9cdbba2127 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts @@ -0,0 +1,66 @@ +import { WizardBundler } from './gql-WizardBundler' +import { WizardFrontendFramework } from './gql-WizardFrontendFramework' +import { WizardNpmPackage } from './gql-WizardNpmPackage' +import { objectType } from 'nexus' +import { CODE_LANGUAGES } from '@packages/types' +import { BUNDLERS, FRONTEND_FRAMEWORKS } from '@packages/scaffold-config' +import { WizardCodeLanguage } from './gql-WizardCodeLanguage' + +export const Wizard = objectType({ + name: 'Wizard', + description: 'The Wizard is a container for any state associated with initial onboarding to Cypress', + definition (t) { + t.nonNull.list.nonNull.field('allBundlers', { + type: WizardBundler, + description: 'All of the bundlers to choose from', + resolve: () => Array.from(BUNDLERS), + }) + + t.field('bundler', { + type: WizardBundler, + resolve: (source, args, ctx) => ctx.wizard.chosenBundler ?? null, + }) + + t.field('framework', { + type: WizardFrontendFramework, + resolve: (source, args, ctx) => ctx.wizard.chosenFramework ?? null, + }) + + t.nonNull.list.nonNull.field('frameworks', { + type: WizardFrontendFramework, + description: 'All of the component testing frameworks to choose from', + resolve: () => Array.from(FRONTEND_FRAMEWORKS), // TODO(tim): fix this in nexus to accept Readonly + }) + + t.field('language', { + type: WizardCodeLanguage, + resolve: (source, args, ctx) => ctx.wizard.chosenLanguage ?? null, + }) + + t.nonNull.list.nonNull.field('allLanguages', { + type: WizardCodeLanguage, + description: 'All of the languages to choose from', + resolve: () => Array.from(CODE_LANGUAGES), // TODO(tim): fix this in nexus to accept Readonly + }) + + t.list.nonNull.field('packagesToInstall', { + type: WizardNpmPackage, + description: 'A list of packages to install, null if we have not chosen both a framework and bundler', + resolve: (source, args, ctx) => ctx.wizard.packagesToInstall(), + }) + + t.list.nonNull.string('installedPackages', { + description: 'The list of packages to install that are currently installed', + resolve: (source, args, ctx) => ctx.wizard.installedPackages(), + }) + + t.string('installDependenciesCommand', { + description: 'Command to install required command', + resolve: (source, args, ctx) => ctx.wizard.installDependenciesCommand(), + }) + }, + sourceType: { + module: '@packages/data-context/src/data/coreDataShape', + export: 'WizardDataShape', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardBundler.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardBundler.ts new file mode 100644 index 0000000000..15491dd078 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardBundler.ts @@ -0,0 +1,33 @@ +import { objectType } from 'nexus' +import { SupportedBundlerEnum, SupportedPackageEnum } from '../enumTypes' + +export const WizardBundler = objectType({ + name: 'WizardBundler', + description: 'Wizard bundler', + node: 'type', + definition (t) { + t.boolean('isSelected', { + description: 'Whether this is the selected framework bundler', + resolve: (source, args, ctx) => ctx.wizardData.chosenBundler === source.type, + }) + + t.nonNull.boolean('isDetected', { + description: 'Whether this is the detected bundler', + resolve: (source, args, ctx) => ctx.wizardData.detectedBundler === source.type, + }) + + t.nonNull.field('type', { + type: SupportedBundlerEnum, + description: 'The name of the framework', + }) + + t.nonNull.string('name', { + description: 'Display name of the bundler', + }) + + t.nonNull.field('package', { + type: SupportedPackageEnum, + description: 'Name of package on npm', + }) + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardCodeLanguage.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardCodeLanguage.ts new file mode 100644 index 0000000000..bdeb61a8c7 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardCodeLanguage.ts @@ -0,0 +1,32 @@ +import { objectType } from 'nexus' +import { CodeLanguageEnum } from '../enumTypes/gql-WizardEnums' + +export const WizardCodeLanguage = objectType({ + name: 'WizardCodeLanguage', + description: 'A code language that the user can choose from to create their cypress.config', + node: 'type', + definition (t) { + t.nonNull.field('type', { + type: CodeLanguageEnum, + description: 'The key of the language', + }) + + t.nonNull.boolean('isSelected', { + description: 'Whether this is the selected language in the wizard', + resolve: (source, args, ctx) => ctx.wizardData.chosenLanguage === source.type, + }) + + t.nonNull.boolean('isDetected', { + description: 'Whether this is the detected language', + resolve: (source, args, ctx) => ctx.wizardData.detectedLanguage === source.type, + }) + + t.nonNull.string('name', { + description: 'The name of the language', + }) + }, + sourceType: { + module: '@packages/types', + export: 'CodeLanguage', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts new file mode 100644 index 0000000000..9d7c455c91 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts @@ -0,0 +1,47 @@ +import { WizardBundler } from './gql-WizardBundler' +import { objectType } from 'nexus' +import { FrontendFrameworkEnum, FrontendFrameworkCategoryEnum } from '../enumTypes/gql-WizardEnums' + +export const WizardFrontendFramework = objectType({ + name: 'WizardFrontendFramework', + description: 'A frontend framework that we can setup within the app', + node: 'type', + definition (t) { + t.nonNull.field('type', { + type: FrontendFrameworkEnum, + description: 'The name of the framework', + }), + + t.nonNull.field('category', { + type: FrontendFrameworkCategoryEnum, + description: 'Classification or label of framework. e.g. React, Vue, or Other', + }) + + t.nonNull.boolean('isSelected', { + description: 'Whether this is the selected framework in the wizard', + resolve: (source, args, ctx) => ctx.wizardData.chosenFramework === source.type, + }) + + t.nonNull.boolean('isDetected', { + description: 'Whether this is the detected framework', + resolve: (source, args, ctx) => ctx.wizardData.detectedFramework === source.type, + }) + + t.nonNull.string('name', { + description: 'The name of the framework', + }) + + t.nonNull.list.nonNull.field('supportedBundlers', { + type: WizardBundler, + description: 'All of the supported bundlers for this framework', + resolve: (source, args, ctx) => { + return [...source.supportedBundlers] + }, + }) + }, + + sourceType: { + module: '@packages/scaffold-config', + export: 'FrontendFramework', + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardNpmPackage.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardNpmPackage.ts new file mode 100644 index 0000000000..ee4c23a2c6 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardNpmPackage.ts @@ -0,0 +1,15 @@ +import { objectType } from 'nexus' + +export const WizardNpmPackage = objectType({ + name: 'WizardNpmPackage', + description: 'Details about an NPM Package listed during the wizard install', + node: 'name', + definition (t) { + t.nonNull.string('name', { + description: 'The package name that you would npm install', + }) + + t.nonNull.string('description') + t.nonNull.string('package') + }, +}) diff --git a/packages/graphql/src/schemaTypes/objectTypes/index.ts b/packages/graphql/src/schemaTypes/objectTypes/index.ts new file mode 100644 index 0000000000..d26046c185 --- /dev/null +++ b/packages/graphql/src/schemaTypes/objectTypes/index.ts @@ -0,0 +1,33 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-AuthState' +export * from './gql-Browser' +export * from './gql-CachedUser' +export * from './gql-CodeFrame' +export * from './gql-CodeGenGlobs' +export * from './gql-CurrentProject' +export * from './gql-DevState' +export * from './gql-Editor' +export * from './gql-ErrorWrapper' +export * from './gql-FileParts' +export * from './gql-GenerateSpecResponse' +export * from './gql-GeneratedSpecError' +export * from './gql-GitInfo' +export * from './gql-GlobalProject' +export * from './gql-LocalSettings' +export * from './gql-Migration' +export * from './gql-Mutation' +export * from './gql-ProjectPreferences' +export * from './gql-Query' +export * from './gql-ScaffoldedFile' +export * from './gql-Spec' +export * from './gql-Subscription' +export * from './gql-TestingTypeInfo' +export * from './gql-Version' +export * from './gql-VersionData' +export * from './gql-Wizard' +export * from './gql-WizardBundler' +export * from './gql-WizardCodeLanguage' +export * from './gql-WizardFrontendFramework' +export * from './gql-WizardNpmPackage' diff --git a/packages/graphql/src/schemaTypes/scalarTypes/gql-customScalars.ts b/packages/graphql/src/schemaTypes/scalarTypes/gql-customScalars.ts new file mode 100644 index 0000000000..c71957be98 --- /dev/null +++ b/packages/graphql/src/schemaTypes/scalarTypes/gql-customScalars.ts @@ -0,0 +1,10 @@ +import { DateTimeResolver, JSONResolver } from 'graphql-scalars' +import { asNexusMethod } from 'nexus' + +// Apollo VSCode is having trouble with this directive +JSONResolver.specifiedByUrl = null + +export const customScalars = [ + asNexusMethod(JSONResolver, 'json'), + asNexusMethod(DateTimeResolver, 'dateTime'), +] diff --git a/packages/graphql/src/schemaTypes/scalarTypes/index.ts b/packages/graphql/src/schemaTypes/scalarTypes/index.ts new file mode 100644 index 0000000000..628d7a541e --- /dev/null +++ b/packages/graphql/src/schemaTypes/scalarTypes/index.ts @@ -0,0 +1,4 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-customScalars' diff --git a/packages/graphql/src/schemaTypes/unions/gql-GeneratedSpecResult.ts b/packages/graphql/src/schemaTypes/unions/gql-GeneratedSpecResult.ts new file mode 100644 index 0000000000..5a38a52a40 --- /dev/null +++ b/packages/graphql/src/schemaTypes/unions/gql-GeneratedSpecResult.ts @@ -0,0 +1,19 @@ +import { unionType } from 'nexus' + +export const GeneratedSpecResult = unionType({ + name: 'GeneratedSpecResult', + definition (t) { + t.members( + 'ScaffoldedFile', + 'GeneratedSpecError', + ) + }, + resolveType: (obj) => { + // @ts-expect-error + if (obj.fileName) { + return 'GeneratedSpecError' + } + + return 'ScaffoldedFile' + }, +}) diff --git a/packages/graphql/src/schemaTypes/unions/index.ts b/packages/graphql/src/schemaTypes/unions/index.ts new file mode 100644 index 0000000000..66f93711cb --- /dev/null +++ b/packages/graphql/src/schemaTypes/unions/index.ts @@ -0,0 +1,4 @@ +/* eslint-disable padding-line-between-statements */ +// created by autobarrel, do not modify directly + +export * from './gql-GeneratedSpecResult' diff --git a/packages/graphql/src/stitching/remoteGraphQLCalls.ts b/packages/graphql/src/stitching/remoteGraphQLCalls.ts new file mode 100644 index 0000000000..40b2ddd979 --- /dev/null +++ b/packages/graphql/src/stitching/remoteGraphQLCalls.ts @@ -0,0 +1,63 @@ +import { batchDelegateToSchema } from '@graphql-tools/batch-delegate' +import type { GraphQLResolveInfo } from 'graphql' +import { remoteSchemaWrapped } from './remoteSchemaWrapped' +import type { Query as CloudQuery } from '../gen/cloud-source-types.gen' +import type { DataContext } from '@packages/data-context' +import { pathToArray } from 'graphql/jsutils/Path' + +type ArrVal = T extends Array ? U : never + +type PotentialFields = Exclude + +interface FieldArgMapping { + cloudProjectsBySlugs: string +} + +interface DelegateToRemoteQueryBatchedConfig { + fieldName: F + info: GraphQLResolveInfo + rootValue?: object + key?: FieldArgMapping[F] + context: DataContext +} + +type KnownBatchFields = PotentialFields & keyof FieldArgMapping + +const FieldConfig: Record = { + cloudProjectsBySlugs: 'slugs', +} + +const IS_PROD = process.env.CYPRESS_INTERNAL_CLOUD_ENV === 'production' + +export function cloudProjectBySlug (slug: string, context: DataContext, info: GraphQLResolveInfo) { + return delegateToRemoteQueryBatched<'cloudProjectsBySlugs'>({ + info, + key: slug, + fieldName: 'cloudProjectsBySlugs', + context, + }) +} + +export async function delegateToRemoteQueryBatched (config: DelegateToRemoteQueryBatchedConfig): Promise | null | Error> { + try { + return await batchDelegateToSchema({ + schema: remoteSchemaWrapped, + info: config.info, + context: config.context, + rootValue: config.rootValue ?? {}, + operation: 'query', + operationName: `${config.info.operation.name?.value ?? 'Unnamed'}_${pathToArray(config.info.path).join('_')}_batched`, + fieldName: config.fieldName, + key: config.key, + argsFromKeys: (keys) => ({ [FieldConfig[config.fieldName]]: keys }), + }) + } catch (e) { + if (IS_PROD) { + config.context.logTraceError(e) + + return null + } + + return e as Error + } +} diff --git a/packages/graphql/src/stitching/remoteSchema.ts b/packages/graphql/src/stitching/remoteSchema.ts new file mode 100644 index 0000000000..b1de542e5e --- /dev/null +++ b/packages/graphql/src/stitching/remoteSchema.ts @@ -0,0 +1,15 @@ +/** + * DIY "Schema Stitching" + * + * Interleaves the remote GraphQL schema with the locally defined schema + * to create a single unified schema for fetching from the client. + */ +import fs from 'fs' +import path from 'path' +import { buildSchema } from 'graphql' + +// Get the Remote schema we've sync'ed locally +export const remoteSchema = buildSchema( + fs.readFileSync(path.join(__dirname, '../../schemas', 'cloud.graphql'), 'utf-8'), + { assumeValid: true }, +) diff --git a/packages/graphql/src/stitching/remoteSchemaExecutor.ts b/packages/graphql/src/stitching/remoteSchemaExecutor.ts new file mode 100644 index 0000000000..6a2ad3c405 --- /dev/null +++ b/packages/graphql/src/stitching/remoteSchemaExecutor.ts @@ -0,0 +1,37 @@ +import { DocumentNode, print } from 'graphql' + +import type { DataContext } from '@packages/data-context' +import type { RequestPolicy } from '@urql/core' + +export interface RemoteExecutionRoot { + requestPolicy?: RequestPolicy +} + +/** + * Takes a "document" and executes it against the GraphQL schema + * @returns + */ +export const remoteSchemaExecutor = async (obj: Record) => { + const { document: _document, operationType, variables, context: _context, rootValue } = obj + + const document: DocumentNode = _document + const context: DataContext = _context + + if (!context?.user) { + return { data: null } + } + + const requestPolicy: RequestPolicy | undefined = rootValue?.requestPolicy ?? null + + const executorResult = await context.cloud.executeRemoteGraphQL({ + operationType, + document, + variables, + query: print(document), + requestPolicy, + }) + + context.debug('executorResult %o', executorResult) + + return executorResult +} diff --git a/packages/graphql/src/stitching/remoteSchemaWrapped.ts b/packages/graphql/src/stitching/remoteSchemaWrapped.ts new file mode 100644 index 0000000000..a5e5e7a4ee --- /dev/null +++ b/packages/graphql/src/stitching/remoteSchemaWrapped.ts @@ -0,0 +1,43 @@ +import { delegateToSchema } from '@graphql-tools/delegate' +import { wrapSchema } from '@graphql-tools/wrap' +import type { GraphQLResolveInfo } from 'graphql' +import { pathToArray } from 'graphql/jsutils/Path' +import { remoteSchema } from './remoteSchema' +import { remoteSchemaExecutor } from './remoteSchemaExecutor' + +// Takes the remote schema & wraps with an "executor", allowing us to delegate +// queries we know should be executed against this server +export const remoteSchemaWrapped = wrapSchema({ + schema: remoteSchema, + executor: remoteSchemaExecutor, + // Needed to ensure the operationName is created / propagated correctly + createProxyingResolver ({ + subschemaConfig, + operation, + transformedSchema, + }) { + return function proxyingResolver (_parent, _args, context, info) { + return delegateToSchema({ + schema: subschemaConfig, + operation, + context, + info, + operationName: getOperationName(info), + transformedSchema, + rootValue: _parent, + }) + } + }, +}) + +/** + * Gives a descriptive GraphQL Operation Name to any queries going out to + * the external schema + */ +function getOperationName (info: GraphQLResolveInfo) { + if (info.operation.name?.value.endsWith('_batched')) { + return info.operation.name?.value + } + + return `${info.operation.name?.value ?? 'Anonymous'}_${pathToArray(info.path).join('_')}` +} diff --git a/packages/graphql/test/.mocharc.js b/packages/graphql/test/.mocharc.js new file mode 100644 index 0000000000..4ba52ba2c8 --- /dev/null +++ b/packages/graphql/test/.mocharc.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/packages/graphql/tsconfig.json b/packages/graphql/tsconfig.json new file mode 100644 index 0000000000..594d9b4f6c --- /dev/null +++ b/packages/graphql/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../ts/tsconfig.json", + "include": [ + "src/*.ts", + "src/**/*.ts" + ], + "exclude": [ + "test", + "script" + ], + "compilerOptions": { + "lib": ["es2020"], + "strict": true, + "allowJs": false, + "noImplicitAny": true, + "noUnusedLocals": false, + "resolveJsonModule": true, + "experimentalDecorators": true, + "noUncheckedIndexedAccess": true, + "importsNotUsedAsValues": "error", + "types": [] + }, +} diff --git a/packages/https-proxy/package.json b/packages/https-proxy/package.json index b91d0e8101..4b77bac00c 100644 --- a/packages/https-proxy/package.json +++ b/packages/https-proxy/package.json @@ -4,7 +4,7 @@ "private": true, "main": "index.js", "scripts": { - "clean-deps": "rm -rf node_modules", + "clean-deps": "rimraf node_modules", "https": "node https.js", "regenerate:certs": "cd ./test/helpers/certs && ./regenerate-certs.sh", "start": "node index.js", @@ -30,6 +30,7 @@ "chai": "3.5.0", "cross-env": "6.0.3", "mocha": "3.5.3", + "rimraf": "3.0.2", "sinon": "1.17.7", "sinon-as-promised": "4.0.3", "sinon-chai": "3.3.0", diff --git a/packages/icons/assets/cypress.iconset/icon_128x128.png b/packages/icons/assets/cypress.iconset/icon_128x128.png new file mode 100644 index 0000000000..87d18c392b Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_128x128.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_128x128@2x.png b/packages/icons/assets/cypress.iconset/icon_128x128@2x.png new file mode 100644 index 0000000000..966abde31c Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_128x128@2x.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_16x16.png b/packages/icons/assets/cypress.iconset/icon_16x16.png new file mode 100644 index 0000000000..c2128095c5 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_16x16.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_16x16@2x.png b/packages/icons/assets/cypress.iconset/icon_16x16@2x.png new file mode 100644 index 0000000000..af9ffeeb63 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_16x16@2x.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_256x256.png b/packages/icons/assets/cypress.iconset/icon_256x256.png new file mode 100644 index 0000000000..b930c90753 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_256x256.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_256x256@2x.png b/packages/icons/assets/cypress.iconset/icon_256x256@2x.png new file mode 100644 index 0000000000..ded004a614 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_256x256@2x.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_32x32.png b/packages/icons/assets/cypress.iconset/icon_32x32.png new file mode 100644 index 0000000000..675ec56fc6 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_32x32.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_32x32@2x.png b/packages/icons/assets/cypress.iconset/icon_32x32@2x.png new file mode 100644 index 0000000000..958416aaaf Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_32x32@2x.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_512x512.png b/packages/icons/assets/cypress.iconset/icon_512x512.png new file mode 100644 index 0000000000..9ed24eaa87 Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_512x512.png differ diff --git a/packages/icons/assets/cypress.iconset/icon_512x512@2x.png b/packages/icons/assets/cypress.iconset/icon_512x512@2x.png new file mode 100644 index 0000000000..859597a34b Binary files /dev/null and b/packages/icons/assets/cypress.iconset/icon_512x512@2x.png differ diff --git a/packages/icons/assets/favicon/favicon.ico b/packages/icons/assets/favicon/favicon.ico new file mode 100644 index 0000000000..99d2af37fa Binary files /dev/null and b/packages/icons/assets/favicon/favicon.ico differ diff --git a/packages/icons/assets/icons/icon_128x128.png b/packages/icons/assets/icons/icon_128x128.png new file mode 100644 index 0000000000..860591c34d Binary files /dev/null and b/packages/icons/assets/icons/icon_128x128.png differ diff --git a/packages/icons/assets/icons/icon_16x16.png b/packages/icons/assets/icons/icon_16x16.png new file mode 100644 index 0000000000..5608c4af21 Binary files /dev/null and b/packages/icons/assets/icons/icon_16x16.png differ diff --git a/packages/icons/assets/icons/icon_19x19.png b/packages/icons/assets/icons/icon_19x19.png new file mode 100644 index 0000000000..c3526420ca Binary files /dev/null and b/packages/icons/assets/icons/icon_19x19.png differ diff --git a/packages/icons/assets/icons/icon_24x24.png b/packages/icons/assets/icons/icon_24x24.png new file mode 100644 index 0000000000..ceedeffc55 Binary files /dev/null and b/packages/icons/assets/icons/icon_24x24.png differ diff --git a/packages/icons/assets/icons/icon_256x256.png b/packages/icons/assets/icons/icon_256x256.png new file mode 100644 index 0000000000..c0fb5baf88 Binary files /dev/null and b/packages/icons/assets/icons/icon_256x256.png differ diff --git a/packages/icons/assets/icons/icon_32x32.png b/packages/icons/assets/icons/icon_32x32.png new file mode 100644 index 0000000000..9d8fcbc521 Binary files /dev/null and b/packages/icons/assets/icons/icon_32x32.png differ diff --git a/packages/icons/assets/icons/icon_38x38.png b/packages/icons/assets/icons/icon_38x38.png new file mode 100644 index 0000000000..793e25fe04 Binary files /dev/null and b/packages/icons/assets/icons/icon_38x38.png differ diff --git a/packages/icons/assets/icons/icon_48x48.png b/packages/icons/assets/icons/icon_48x48.png new file mode 100644 index 0000000000..393c6e79cd Binary files /dev/null and b/packages/icons/assets/icons/icon_48x48.png differ diff --git a/packages/icons/assets/icons/icon_48x48@2x.png b/packages/icons/assets/icons/icon_48x48@2x.png new file mode 100644 index 0000000000..7dc2be25e7 Binary files /dev/null and b/packages/icons/assets/icons/icon_48x48@2x.png differ diff --git a/packages/icons/assets/icons/icon_64x64.png b/packages/icons/assets/icons/icon_64x64.png new file mode 100644 index 0000000000..4424888725 Binary files /dev/null and b/packages/icons/assets/icons/icon_64x64.png differ diff --git a/packages/icons/assets/logo/cypress-bw.png b/packages/icons/assets/logo/cypress-bw.png new file mode 100644 index 0000000000..c02e99880b Binary files /dev/null and b/packages/icons/assets/logo/cypress-bw.png differ diff --git a/packages/icons/index.d.ts b/packages/icons/index.d.ts new file mode 100644 index 0000000000..c28237ffe7 --- /dev/null +++ b/packages/icons/index.d.ts @@ -0,0 +1 @@ +export * from './dist/icons' \ No newline at end of file diff --git a/packages/icons/index.js b/packages/icons/index.js new file mode 100644 index 0000000000..472bf21cc8 --- /dev/null +++ b/packages/icons/index.js @@ -0,0 +1 @@ +module.exports = require('./dist/icons') diff --git a/packages/icons/package.json b/packages/icons/package.json new file mode 100644 index 0000000000..02feff9fef --- /dev/null +++ b/packages/icons/package.json @@ -0,0 +1,28 @@ +{ + "name": "@packages/icons", + "version": "0.0.0-development", + "description": "Cypress Icons", + "private": true, + "main": "index.js", + "scripts": { + "build-prod": "yarn build", + "build": "ts-node ./scripts/build.ts && ts-node ./src/ico.ts", + "test-unit": "NODE_ENV=test mocha -r @packages/ts/register test/*.ts", + "test": "yarn test-unit" + }, + "devDependencies": { + "@types/mocha": "^8.0.3", + "@types/to-ico": "^1.1.1", + "chai": "^4.2.0", + "fs-extra": "9.1.0", + "mocha": "^8.1.3", + "to-ico": "^1.1.5" + }, + "files": [ + "dist", + "index.js", + "index.d.ts" + ], + "license": "MIT", + "author": "Brian Mann" +} diff --git a/packages/icons/readme.md b/packages/icons/readme.md new file mode 100644 index 0000000000..1cc783edba --- /dev/null +++ b/packages/icons/readme.md @@ -0,0 +1,43 @@ +# Cypress Icons + +The latest versions of the icons. +The public API will always reference these files. + +`./dist` is not checked into source control. + +## API + +```js +const icons = require("@cypress/icons") + +// get the absolute path to default favicon +icons.getPathToFavicon("favicon-blue.ico") +// => /Users/.../dist/favicon/favicon-blue.ico + +// get the absolute path to icon +icons.getPathToIcon("icon_32x32@2x.png") +// => /Users/.../dist/icons/icon_32x32@2x.png +``` + +## Architecture detail + +To build the MacOS icons you have to use the `iconutil` command line tool installed. +This command line tool is only installed on MacOS. + +If you are not on MacOS, the building of this icon will simply be skipped. +If you are not on MacOS, the building of this icon will be skipped instead of erroring. + +## Developing + +All the icons are in the assets directory. + +```bash +## run build to dump to ./dist +yarn build +``` + +## Testing + +```bash +yarn test +``` diff --git a/packages/icons/scripts/build.ts b/packages/icons/scripts/build.ts new file mode 100644 index 0000000000..5c7f6edc1e --- /dev/null +++ b/packages/icons/scripts/build.ts @@ -0,0 +1,26 @@ +import fs from 'fs-extra' +import path from 'path' +import { exec } from 'child_process' +import os from 'os' + +async function build () { + const distPath = path.join(__dirname, '../dist') + const assetsPath = path.join(__dirname, '../assets') + const iconsPath = path.join(distPath, 'icons') + const iconsetPath = path.join(distPath, 'cypress.iconset') + + await fs.remove(distPath) + await fs.mkdir(iconsPath, { recursive: true }) + + await exec('yarn tsc -p ./tsconfig.build.json') + + if (os.platform() === 'darwin') { + await exec('iconutil -c icns assets/cypress.iconset -o dist/icons/cypress.icns') + } + + await fs.copy(assetsPath, distPath) + await fs.copy(iconsetPath, iconsPath, { overwrite: true }) + await fs.remove(iconsetPath) +} + +build() diff --git a/packages/icons/src/ico.ts b/packages/icons/src/ico.ts new file mode 100644 index 0000000000..5fd77a0a4e --- /dev/null +++ b/packages/icons/src/ico.ts @@ -0,0 +1,16 @@ +import fs from 'fs' +import toIco from 'to-ico' + +const files = [ + fs.readFileSync('./assets/icons/icon_16x16.png'), + fs.readFileSync('./assets/icons/icon_24x24.png'), + fs.readFileSync('./assets/icons/icon_32x32.png'), + fs.readFileSync('./assets/icons/icon_48x48.png'), + fs.readFileSync('./assets/icons/icon_64x64.png'), + fs.readFileSync('./assets/icons/icon_128x128.png'), + fs.readFileSync('./assets/icons/icon_256x256.png'), +] + +toIco(files).then((buf) => { + fs.writeFileSync('./dist/icons/cypress.ico', buf) +}) diff --git a/packages/icons/src/icons.ts b/packages/icons/src/icons.ts new file mode 100644 index 0000000000..ef9751143c --- /dev/null +++ b/packages/icons/src/icons.ts @@ -0,0 +1,19 @@ +import path from 'path' + +const dist = [__dirname, '..', 'dist'] + +function distPath (...args: string[]) { + return path.join.apply(path, dist.concat([...args])) +} + +export const getPathToFavicon = (filename: string) => { + return distPath('favicon', filename) +} + +export const getPathToIcon = (filename: string) => { + return distPath('icons', filename) +} + +export const getPathToLogo = (filename: string) => { + return distPath('logo', filename) +} diff --git a/packages/icons/test/icons_spec.ts b/packages/icons/test/icons_spec.ts new file mode 100644 index 0000000000..09622d4c01 --- /dev/null +++ b/packages/icons/test/icons_spec.ts @@ -0,0 +1,18 @@ +import { expect } from 'chai' +import * as icons from '../src/icons' + +const cwd = process.cwd() + +describe('Cypress Icons', function () { + it('returns path to favicon', function () { + expect(icons.getPathToFavicon('favicon-red.ico')).to.eq(`${cwd }/dist/favicon/favicon-red.ico`) + }) + + it('returns path to icon', function () { + expect(icons.getPathToIcon('cypress.icns')).to.eq(`${cwd }/dist/icons/cypress.icns`) + }) + + it('returns path to logo', function () { + expect(icons.getPathToLogo('cypress-bw.png')).to.eq(`${cwd }/dist/logo/cypress-bw.png`) + }) +}) diff --git a/packages/icons/tsconfig.build.json b/packages/icons/tsconfig.build.json new file mode 100644 index 0000000000..e177dd467b --- /dev/null +++ b/packages/icons/tsconfig.build.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "files": [ + "./src/icons.ts" + ] +} \ No newline at end of file diff --git a/packages/icons/tsconfig.json b/packages/icons/tsconfig.json new file mode 100644 index 0000000000..7fd743fc6d --- /dev/null +++ b/packages/icons/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../ts/tsconfig.json", + "compilerOptions": { + "strict": true, + "allowJs": false, + "noImplicitAny": true, + "noUnusedLocals": false, + "resolveJsonModule": true, + "experimentalDecorators": true, + "noUncheckedIndexedAccess": true, + "importsNotUsedAsValues": "error", + "outDir": "dist", + "declaration": true + }, +} \ No newline at end of file diff --git a/packages/launcher/__snapshots__/darwin_spec.ts.js b/packages/launcher/__snapshots__/darwin_spec.ts.js index 9be90df64b..211300074b 100644 --- a/packages/launcher/__snapshots__/darwin_spec.ts.js +++ b/packages/launcher/__snapshots__/darwin_spec.ts.js @@ -82,11 +82,11 @@ exports['darwin browser detection detects browsers as expected 1'] = [ "versionRegex": {}, "binary": "firefox", "minSupportedVersion": 86, - "path": "/Applications/Firefox.app/Contents/MacOS/firefox-bin", + "path": "/Applications/Firefox.app/Contents/MacOS/firefox", "version": "someVersion", "findAppParams": { "appName": "Firefox.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefox", "versionProperty": "CFBundleShortVersionString" } @@ -102,11 +102,11 @@ exports['darwin browser detection detects browsers as expected 1'] = [ "firefox" ], "minSupportedVersion": 86, - "path": "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox-bin", + "path": "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox", "version": "someVersion", "findAppParams": { "appName": "Firefox Developer Edition.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefoxdeveloperedition", "versionProperty": "CFBundleShortVersionString" } @@ -122,11 +122,11 @@ exports['darwin browser detection detects browsers as expected 1'] = [ "firefox-trunk" ], "minSupportedVersion": 86, - "path": "/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin", + "path": "/Applications/Firefox Nightly.app/Contents/MacOS/firefox", "version": "someVersion", "findAppParams": { "appName": "Firefox Nightly.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.nightly", "versionProperty": "CFBundleShortVersionString" } diff --git a/packages/launcher/__snapshots__/windows_spec.ts.js b/packages/launcher/__snapshots__/windows_spec.ts.js index 59264eb06d..a13054d205 100644 --- a/packages/launcher/__snapshots__/windows_spec.ts.js +++ b/packages/launcher/__snapshots__/windows_spec.ts.js @@ -86,7 +86,7 @@ exports['windows browser detection detects browsers as expected 1'] = [ "version": "72", "findAppParams": { "appName": "Firefox.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefox", "versionProperty": "CFBundleShortVersionString" } @@ -106,7 +106,7 @@ exports['windows browser detection detects browsers as expected 1'] = [ "version": "73", "findAppParams": { "appName": "Firefox Developer Edition.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefoxdeveloperedition", "versionProperty": "CFBundleShortVersionString" } @@ -126,7 +126,7 @@ exports['windows browser detection detects browsers as expected 1'] = [ "version": "74", "findAppParams": { "appName": "Firefox Nightly.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.nightly", "versionProperty": "CFBundleShortVersionString" } @@ -232,7 +232,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [ "version": "100", "findAppParams": { "appName": "Firefox.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefox", "versionProperty": "CFBundleShortVersionString" } @@ -252,7 +252,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [ "version": "300", "findAppParams": { "appName": "Firefox Developer Edition.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.firefoxdeveloperedition", "versionProperty": "CFBundleShortVersionString" } @@ -272,7 +272,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [ "version": "200", "findAppParams": { "appName": "Firefox Nightly.app", - "executable": "Contents/MacOS/firefox-bin", + "executable": "Contents/MacOS/firefox", "appId": "org.mozilla.nightly", "versionProperty": "CFBundleShortVersionString" } diff --git a/packages/launcher/lib/browsers.ts b/packages/launcher/lib/browsers.ts index 22dae9ec01..904d365e17 100644 --- a/packages/launcher/lib/browsers.ts +++ b/packages/launcher/lib/browsers.ts @@ -1,130 +1,23 @@ import { log } from './log' import * as cp from 'child_process' -import type { Browser, FoundBrowser } from './types' +import { browsers, FoundBrowser } from '@packages/types' +import type { Readable } from 'stream' -// Chrome started exposing CDP 1.3 in 64 -const MIN_CHROME_VERSION = 64 -// Firefox started exposing CDP in 86 -const MIN_FIREFOX_VERSION = 86 -// Edge switched to Blink in 79 -const MIN_EDGE_VERSION = 79 +export { browsers } /** list of the browsers we can detect and use by default */ -export const browsers: Browser[] = [ - { - name: 'chrome', - family: 'chromium', - channel: 'stable', - displayName: 'Chrome', - versionRegex: /Google Chrome (\S+)/m, - binary: ['google-chrome', 'chrome', 'google-chrome-stable'], - minSupportedVersion: MIN_CHROME_VERSION, - }, - { - name: 'chromium', - family: 'chromium', - // technically Chromium is always in development - channel: 'stable', - displayName: 'Chromium', - versionRegex: /Chromium (\S+)/m, - binary: ['chromium-browser', 'chromium'], - minSupportedVersion: MIN_CHROME_VERSION, - }, - { - name: 'chrome', - family: 'chromium', - channel: 'beta', - displayName: 'Chrome Beta', - versionRegex: /Google Chrome (\S+) beta/m, - binary: 'google-chrome-beta', - minSupportedVersion: MIN_CHROME_VERSION, - }, - { - name: 'chrome', - family: 'chromium', - channel: 'canary', - displayName: 'Canary', - versionRegex: /Google Chrome Canary (\S+)/m, - binary: 'google-chrome-canary', - minSupportedVersion: MIN_CHROME_VERSION, - }, - { - name: 'firefox', - family: 'firefox', - channel: 'stable', - displayName: 'Firefox', - // Mozilla Firefox 70.0.1 - versionRegex: /^Mozilla Firefox ([^\sab]+)$/m, - binary: 'firefox', - minSupportedVersion: MIN_FIREFOX_VERSION, - }, - { - name: 'firefox', - family: 'firefox', - channel: 'dev', - displayName: 'Firefox Developer Edition', - // Mozilla Firefox 73.0b12 - versionRegex: /^Mozilla Firefox (\S+b\S*)$/m, - // ubuntu PPAs install it as firefox - binary: ['firefox-developer-edition', 'firefox'], - minSupportedVersion: MIN_FIREFOX_VERSION, - }, - { - name: 'firefox', - family: 'firefox', - channel: 'nightly', - displayName: 'Firefox Nightly', - // Mozilla Firefox 74.0a1 - versionRegex: /^Mozilla Firefox (\S+a\S*)$/m, - // ubuntu PPAs install it as firefox-trunk - binary: ['firefox-nightly', 'firefox-trunk'], - minSupportedVersion: MIN_FIREFOX_VERSION, - }, - { - name: 'edge', - family: 'chromium', - channel: 'stable', - displayName: 'Edge', - versionRegex: /Microsoft Edge (\S+)/m, - binary: ['edge', 'microsoft-edge'], - minSupportedVersion: MIN_EDGE_VERSION, - }, - { - name: 'edge', - family: 'chromium', - channel: 'canary', - displayName: 'Edge Canary', - versionRegex: /Microsoft Edge Canary (\S+)/m, - binary: 'edge-canary', - minSupportedVersion: MIN_EDGE_VERSION, - }, - { - name: 'edge', - family: 'chromium', - channel: 'beta', - displayName: 'Edge Beta', - versionRegex: /Microsoft Edge Beta (\S+)/m, - binary: 'edge-beta', - minSupportedVersion: MIN_EDGE_VERSION, - }, - { - name: 'edge', - family: 'chromium', - channel: 'dev', - displayName: 'Edge Dev', - versionRegex: /Microsoft Edge Dev (\S+)/m, - binary: ['edge-dev', 'microsoft-edge-dev'], - minSupportedVersion: MIN_EDGE_VERSION, - }, -] /** starts a found browser and opens URL if given one */ + +export type LaunchedBrowser = cp.ChildProcessByStdio + export function launch ( browser: FoundBrowser, url: string, + debuggingPort: number, args: string[] = [], defaultBrowserEnv = {}, -) { +): LaunchedBrowser { log('launching browser %o', { browser, url }) if (!browser.path) { diff --git a/packages/launcher/lib/darwin/index.ts b/packages/launcher/lib/darwin/index.ts index ed8639ca33..1efe0a9239 100644 --- a/packages/launcher/lib/darwin/index.ts +++ b/packages/launcher/lib/darwin/index.ts @@ -1,5 +1,5 @@ import { findApp, FindAppParams } from './util' -import type { Browser, DetectedBrowser } from '../types' +import type { Browser, DetectedBrowser } from '@packages/types' import * as linuxHelper from '../linux' import { log } from '../log' import { get } from 'lodash' @@ -42,19 +42,19 @@ export const browsers: Detectors = { firefox: { stable: { appName: 'Firefox.app', - executable: 'Contents/MacOS/firefox-bin', + executable: 'Contents/MacOS/firefox', appId: 'org.mozilla.firefox', versionProperty: 'CFBundleShortVersionString', }, dev: { appName: 'Firefox Developer Edition.app', - executable: 'Contents/MacOS/firefox-bin', + executable: 'Contents/MacOS/firefox', appId: 'org.mozilla.firefoxdeveloperedition', versionProperty: 'CFBundleShortVersionString', }, nightly: { appName: 'Firefox Nightly.app', - executable: 'Contents/MacOS/firefox-bin', + executable: 'Contents/MacOS/firefox', appId: 'org.mozilla.nightly', versionProperty: 'CFBundleShortVersionString', }, diff --git a/packages/launcher/lib/darwin/util.ts b/packages/launcher/lib/darwin/util.ts index 9447bcf7bf..8327ec7eb5 100644 --- a/packages/launcher/lib/darwin/util.ts +++ b/packages/launcher/lib/darwin/util.ts @@ -6,7 +6,7 @@ import * as os from 'os' import * as path from 'path' import * as plist from 'plist' import * as semver from 'semver' -import type { FoundBrowser } from '../types' +import type { FoundBrowser } from '@packages/types' import * as findSystemNode from '@packages/server/lib/util/find_system_node' /** parses Info.plist file from given application and returns a property */ diff --git a/packages/launcher/lib/detect.ts b/packages/launcher/lib/detect.ts index 55ff07349e..f661e8c4a9 100644 --- a/packages/launcher/lib/detect.ts +++ b/packages/launcher/lib/detect.ts @@ -11,6 +11,8 @@ import type { Browser, DetectedBrowser, FoundBrowser, +} from '@packages/types' +import type { NotDetectedAtPathError, NotInstalledError, PathData, } from './types' @@ -22,7 +24,8 @@ type HasVersion = Omit, 'version' | 'name'> & { } export const setMajorVersion = (browser: T): T => { - const majorVersion = parseInt(browser.version.split('.')[0]) || browser.version + const ver = browser.version.split('.')[0] ?? browser.version + const majorVersion = parseInt(ver) || browser.version const unsupportedVersion = browser.minSupportedVersion && majorVersion < browser.minSupportedVersion @@ -62,7 +65,13 @@ const helpers: Helpers = { } function getHelper (platform?: NodeJS.Platform): PlatformHelper { - return helpers[platform || os.platform()] + const helper = helpers[platform || os.platform()] + + if (!helper) { + throw Error(`Could not find helper for ${platform}`) + } + + return helper } function lookup ( diff --git a/packages/launcher/lib/linux/index.ts b/packages/launcher/lib/linux/index.ts index c09fca1dd3..3b59fd0370 100644 --- a/packages/launcher/lib/linux/index.ts +++ b/packages/launcher/lib/linux/index.ts @@ -1,5 +1,6 @@ import { log } from '../log' -import type { FoundBrowser, Browser, PathData } from '../types' +import type { FoundBrowser, Browser } from '@packages/types' +import type { PathData } from '../types' import { notInstalledErr } from '../errors' import { utils } from '../utils' import os from 'os' @@ -54,7 +55,7 @@ function getLinuxBrowser ( return getVersionString(binary) .tap(maybeSetSnapProfilePath) .then(getVersion) - .then((version: string): FoundBrowser => { + .then((version?: string): FoundBrowser => { foundBrowser.version = version return foundBrowser @@ -79,7 +80,7 @@ export function getVersionString (path: string) { export function getVersionNumber (version: string, browser: Browser) { const regexExec = browser.versionRegex.exec(version) as Array - return regexExec ? regexExec[1] : version + return (regexExec && regexExec[1]) ?? version } export function getPathData (pathStr: string): PathData { diff --git a/packages/launcher/lib/types.ts b/packages/launcher/lib/types.ts index 1ba2f7a43b..bc08c1fdbb 100644 --- a/packages/launcher/lib/types.ts +++ b/packages/launcher/lib/types.ts @@ -1,70 +1,6 @@ import type { ChildProcess } from 'child_process' import type Bluebird from 'bluebird' - -// TODO: Clean up this file - -// TODO: some of these types can be combined with cli/types/index.d.ts - -type BrowserName = 'electron' | 'chrome' | 'chromium' | 'firefox' | string - -type BrowserChannel = 'stable' | 'canary' | 'beta' | 'dev' | 'nightly' | string - -type BrowserFamily = 'chromium' | 'firefox' - -export type PlatformName = 'darwin' | 'linux' | 'win32' - -/** - * Represents a typical browser to try to detect and turn into a `FoundBrowser`. - */ -export type Browser = { - /** - * Short browser name. - */ - name: BrowserName - /** - * The underlying engine for this browser. - */ - family: BrowserFamily - /** - * The release channel of the browser. - */ - channel: BrowserChannel - /** - * Human-readable browser name. - */ - displayName: string - /** RegExp to use to extract version from something like "Google Chrome 58.0.3029.110" */ - versionRegex: RegExp - /** If set, this is the base path that will be used for setting userDataDir. Useful for creating profiles in snap confinement. */ - profilePath?: string - /** A single binary name or array of binary names for this browser. Not used on Windows. */ - binary: string | string[] - /** optional warning that will be shown in the GUI */ - warning?: string - /** optional info that will be shown in the GUI */ - info?: string - /** if set, the majorVersion must be >= this to be run in Cypress */ - minSupportedVersion?: number -} - -/** - * Represents a real browser that exists on the user's system. - */ -export type FoundBrowser = Omit & { - path: string - version: string - majorVersion?: string - /** is this a user-supplied browser? */ - custom?: boolean - unsupportedVersion?: boolean -} - -/** - * Partial browser object, returned by an OS-specific launcher helper. - */ -export type DetectedBrowser = Pick - -// all common type definition for this module +import type { Browser, FoundBrowser } from '@packages/types' export type NotInstalledError = Error & { notInstalled: boolean } diff --git a/packages/launcher/lib/windows/index.ts b/packages/launcher/lib/windows/index.ts index 128b90539f..b3842759d9 100644 --- a/packages/launcher/lib/windows/index.ts +++ b/packages/launcher/lib/windows/index.ts @@ -1,11 +1,12 @@ import * as fse from 'fs-extra' +import winVersionInfo from 'win-version-info' import os from 'os' import { join, normalize, win32 } from 'path' import { get } from 'lodash' import { notInstalledErr } from '../errors' import { log } from '../log' -import type { Browser, FoundBrowser, PathData } from '../types' -import { utils } from '../utils' +import type { PathData } from '../types' +import type { Browser, FoundBrowser } from '@packages/types' function formFullAppPath (name: string) { return [ @@ -110,20 +111,6 @@ const formPaths: WindowsBrowserPaths = { } function getWindowsBrowser (browser: Browser): Promise { - const getVersion = (stdout: string): string => { - // result from wmic datafile - // "Version=61.0.3163.100" - const wmicVersion = /^Version=(\S+)$/ - const m = wmicVersion.exec(stdout) - - if (m) { - return m[1] - } - - log('Could not extract version from %s using regex %s', stdout, wmicVersion) - throw notInstalledErr(browser.name) - } - const formFullAppPathFn: NameToPath = get(formPaths, [browser.name, browser.channel], formFullAppPath) const exePaths = formFullAppPathFn(browser.name) @@ -149,14 +136,9 @@ function getWindowsBrowser (browser: Browser): Promise { return tryNextExePath() } - return getVersionString(path) - .then((val) => { - log(val) - - return val - }) - .then(getVersion) - .then((version: string) => { + // Use exports.getVersionString here, rather than our local reference + // to that variable so that the tests can easily mock it + return exports.getVersionString(path).then((version) => { log('browser %s at \'%s\' version %s', browser.name, exePath, version) return { @@ -186,23 +168,20 @@ export function getVersionString (path: string) { // on Windows using "--version" seems to always start the full // browser, no matter what one does. - const args = [ - 'datafile', - 'where', - `name="${path}"`, - 'get', - 'Version', - '/value', - ] - - return utils.execa('wmic', args) - .then((val) => val.stdout) - .then((val) => val.trim()) + try { + return Promise.resolve(winVersionInfo(path).FileVersion) + } catch (err) { + return Promise.reject(err) + } } export function getVersionNumber (version: string) { if (version.indexOf('Version=') > -1) { - return version.split('=')[1] + const split = version.split('=') + + if (split[1]) { + return split[1] + } } return version diff --git a/packages/launcher/package.json b/packages/launcher/package.json index 9e569f4482..2a10a6dc40 100644 --- a/packages/launcher/package.json +++ b/packages/launcher/package.json @@ -4,8 +4,8 @@ "private": true, "scripts": { "build-prod": "tsc --project .", - "clean": "node scripts/clean.js || true", - "clean-deps": "rm -rf node_modules", + "clean": "rimraf --glob \"lib/*.js\" && rimraf --glob \"lib/**/*.js\" || true", + "clean-deps": "rimraf node_modules", "clean-js": "yarn clean", "size": "t=\"cypress-v0.0.0.tgz\"; yarn pack --filename \"${t}\"; wc -c \"cli/${t}\"; tar tvf \"${t}\"; rm \"${t}\";", "test": "yarn test-unit", @@ -18,15 +18,17 @@ "fs-extra": "9.1.0", "lodash": "^4.17.21", "plist": "3.0.5", - "semver": "7.3.5" + "semver": "7.3.5", + "win-version-info": "5.0.1" }, "devDependencies": { "@packages/ts": "0.0.0-development", + "@packages/types": "0.0.0-development", "chai": "3.5.0", "chai-as-promised": "7.1.1", "cross-env": "6.0.3", "mocha": "3.5.3", - "shelljs": "0.8.5", + "rimraf": "3.0.2", "sinon": "^10.0.0", "sinon-chai": "3.4.0", "typescript": "^4.2.3" diff --git a/packages/launcher/scripts/clean.js b/packages/launcher/scripts/clean.js deleted file mode 100644 index 32b3ab2d32..0000000000 --- a/packages/launcher/scripts/clean.js +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env node - -const shell = require('shelljs') - -shell.set('-v') // verbose - -shell.rm('lib/*.js') -shell.rm('lib/**/*.js') diff --git a/packages/launcher/test/unit/windows_spec.ts b/packages/launcher/test/unit/windows_spec.ts index fe8cdd99ce..5503184709 100644 --- a/packages/launcher/test/unit/windows_spec.ts +++ b/packages/launcher/test/unit/windows_spec.ts @@ -2,23 +2,22 @@ import _ from 'lodash' import { expect } from 'chai' import * as windowsHelper from '../../lib/windows' import { normalize } from 'path' -import { utils } from '../../lib/utils' import sinon, { SinonStub } from 'sinon' import { browsers } from '../../lib/browsers' import Bluebird from 'bluebird' import fse from 'fs-extra' import os from 'os' import snapshot from 'snap-shot-it' -import { Browser } from '../../lib/types' +import type { Browser } from '@packages/types' import { detectByPath } from '../../lib/detect' import { goalBrowsers } from '../fixtures' function stubBrowser (path: string, version: string) { path = windowsHelper.doubleEscape(normalize(path)) - ;(utils.execa as unknown as SinonStub) - .withArgs('wmic', ['datafile', 'where', `name="${path}"`, 'get', 'Version', '/value']) - .resolves({ stdout: `Version=${version}` }) + ;(windowsHelper.getVersionString as unknown as SinonStub) + .withArgs(path) + .resolves(version) ;(fse.pathExists as SinonStub) .withArgs(path) @@ -40,7 +39,7 @@ describe('windows browser detection', () => { beforeEach(() => { sinon.stub(fse, 'pathExists').resolves(false) sinon.stub(os, 'homedir').returns(HOMEDIR) - sinon.stub(utils, 'execa').rejects() + sinon.stub(windowsHelper, 'getVersionString').rejects() }) it('detects browsers as expected', async () => { @@ -145,20 +144,10 @@ describe('windows browser detection', () => { }) context('#getVersionString', () => { - it('runs wmic and returns output', async () => { + it('returns the FileVersion from win-version-info', async () => { stubBrowser('foo', 'bar') - expect(await windowsHelper.getVersionString('foo')).to.eq('Version=bar') - }) - - it('rejects with errors', async () => { - const err = new Error() - - ;(utils.execa as unknown as SinonStub) - .withArgs('wmic', ['datafile', 'where', 'name="foo"', 'get', 'Version', '/value']) - .rejects(err) - - await expect(windowsHelper.getVersionString('foo')).to.be.rejectedWith(err) + expect(await windowsHelper.getVersionString('foo')).to.eq('bar') }) }) diff --git a/packages/launcher/tsconfig.json b/packages/launcher/tsconfig.json index d337de179d..22cbe18d5c 100644 --- a/packages/launcher/tsconfig.json +++ b/packages/launcher/tsconfig.json @@ -4,6 +4,9 @@ "**/*.ts", "./index.ts" ], + "compilerOptions": { + "skipLibCheck": true + }, "files": [ "./../ts/index.d.ts" ], diff --git a/packages/launchpad/.eslintrc.json b/packages/launchpad/.eslintrc.json new file mode 100644 index 0000000000..4a8d21e6c6 --- /dev/null +++ b/packages/launchpad/.eslintrc.json @@ -0,0 +1,78 @@ +{ + "globals": { + "defineProps": "readonly", + "defineEmits": "readonly", + "defineExpose": "readonly", + "withDefaults": "readonly" + }, + "plugins": [ + "cypress", + "@cypress/dev" + ], + "extends": [ + "../frontend-shared/.eslintrc.json" + ], + "env": { + "cypress/globals": true + }, + "rules": {}, + "overrides": [ + { + "files": "**/*.vue", + "rules": { + "vue/no-v-html": "off", + "vue/multiline-html-element-content-newline": [ + "warn", + { + "ignoreWhenEmpty": true, + "ignores": [ + "pre", + "textarea", + "code", + "CodeTag" + ], + "allowEmptyLines": false + } + ], + "no-spaced-func": "off", + "no-restricted-imports": [ + "error", + { + "patterns": [ + "@packages/graphql/*" + ] + } + ] + } + }, + { + "files": [ + "lib/*" + ], + "rules": { + "no-console": 1 + } + }, + { + "files": [ + "**/*.json" + ], + "rules": { + "quotes": "off", + "comma-dangle": "off" + } + }, + { + "files": [ + "*.tsx", + "*.jsx" + ], + "rules": { + "no-unused-vars": "off", + "react/jsx-no-bind": "off", + "react/react-in-jsx-scope": "off", + "react/no-unknown-property": "off" + } + } + ] +} \ No newline at end of file diff --git a/packages/launchpad/.gitignore b/packages/launchpad/.gitignore new file mode 100644 index 0000000000..86e379ad67 --- /dev/null +++ b/packages/launchpad/.gitignore @@ -0,0 +1,2 @@ +cypress/videos/* +cypress/screenshots/* \ No newline at end of file diff --git a/packages/launchpad/.percy.yml b/packages/launchpad/.percy.yml new file mode 100644 index 0000000000..b4289dae89 --- /dev/null +++ b/packages/launchpad/.percy.yml @@ -0,0 +1,7 @@ +version: 2 +snapshot: + widths: + - 1280 + min-height: 1024 +discovery: + network-idle-timeout: 1000 diff --git a/packages/launchpad/README.md b/packages/launchpad/README.md new file mode 100644 index 0000000000..89594fc776 --- /dev/null +++ b/packages/launchpad/README.md @@ -0,0 +1,82 @@ +# Launchpad + +Launchpad is next-gen Vue application that is rendered by Electron. This acts as the visual user interface you see when running: `cypress open`. + +It replaces the original electron app, `desktop-gui`. + +**Launchpad has the following responsibilities:** + +- Allow users to log in through the Dashboard Service +- Onboarding for new users (configure Component Testing dev server, install dependencies, etc) +- Select testing mode (E2E, Component, Node.js) + +It is using the following technologies: + +- [Vue 3](https://v3.vuejs.org/guide/introduction.html) for the UI framework + - code is written with the [Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html) + - uses the new [` + + diff --git a/packages/launchpad/package.json b/packages/launchpad/package.json new file mode 100644 index 0000000000..bc45b9b65e --- /dev/null +++ b/packages/launchpad/package.json @@ -0,0 +1,123 @@ +{ + "name": "@packages/launchpad", + "version": "0.0.0-development", + "private": true, + "scripts": { + "check-ts": "vue-tsc --noEmit", + "build-prod-ui": "cross-env NODE_ENV=production vite build", + "clean": "rimraf dist && rimraf ./node_modules/.vite && rimraf dist-e2e && echo 'cleaned'", + "clean-deps": "rimraf node_modules", + "test": "yarn cypress:run:ct && yarn types", + "windi": "yarn windicss-analysis", + "cypress:open": "cross-env TZ=America/New_York gulp open --project .", + "cypress:open:ct": "cross-env TZ=America/New_York gulp open --component --project .", + "cypress:run:ct": "cross-env TZ=America/New_York node ../../scripts/cypress run --component --project .", + "cypress:run:e2e": "cross-env TZ=America/New_York node ../../scripts/cypress run --e2e --project .", + "dev": "yarn gulp dev --project .", + "start": "echo 'run yarn dev from the root' && exit 1", + "watch": "echo 'run yarn dev from the root' && exit 1" + }, + "dependencies": {}, + "devDependencies": { + "@cypress/vue": "0.0.0-development", + "@graphql-typed-document-node/core": "^3.1.0", + "@headlessui/vue": "1.4.0", + "@iconify/iconify": "2.1.2", + "@iconify/json": "1.1.368", + "@iconify/vue": "3.0.0-beta.1", + "@intlify/vite-plugin-vue-i18n": "2.4.0", + "@packages/frontend-shared": "0.0.0-development", + "@percy/cypress": "^3.1.0", + "@purge-icons/generated": "0.8.1", + "@testing-library/cypress": "8.0.0", + "@tooling/system-tests": "0.0.0-development", + "@toycode/markdown-it-class": "1.2.3", + "@types/dedent": "^0.7.0", + "@types/fs-extra": "^8.0.1", + "@urql/core": "2.3.1", + "@urql/devtools": "2.0.3", + "@urql/vue": "0.4.3", + "@vitejs/plugin-vue": "2.2.4", + "@vitejs/plugin-vue-jsx": "1.3.8", + "@vue/compiler-core": "3.2.31", + "@vue/compiler-dom": "3.2.31", + "@vue/compiler-sfc": "3.2.31", + "@vueuse/core": "7.2.2", + "bluebird": "3.5.3", + "classnames": "2.3.1", + "concurrently": "^6.2.0", + "cross-env": "6.0.3", + "cypress-plugin-tab": "1.0.5", + "cypress-real-events": "1.6.0", + "dedent": "^0.7.0", + "disparity": "^3.0.0", + "fs-extra": "8.1.0", + "globby": "^11.0.1", + "graphql": "^15.5.1", + "graphql-tag": "^2.12.5", + "gravatar": "1.8.0", + "javascript-time-ago": "2.3.8", + "markdown-it": "12.2.0", + "rimraf": "3.0.2", + "rollup-plugin-polyfill-node": "^0.7.0", + "type-fest": "^2.3.4", + "vite": "2.9.0-beta.3", + "vite-plugin-components": "0.11.3", + "vite-plugin-optimize-persist": "0.0.5", + "vite-plugin-package-config": "0.0.3", + "vite-plugin-windicss": "1.2.4", + "vite-svg-loader": "3.1.2", + "vue": "3.2.31", + "vue-i18n": "9.2.0-beta.7", + "vue-tsc": "^0.3.0", + "vue3-file-selector": "^1.0.1", + "windicss": "3.1.4", + "windicss-analysis": "^0.3.4", + "wonka": "^4.0.15" + }, + "files": [ + "dist", + "lib", + "script", + "src" + ], + "vite": { + "optimizeDeps": { + "include": [ + "@headlessui/vue", + "@iconify/iconify", + "@iconify/vue", + "@percy/cypress", + "@purge-icons/generated", + "@testing-library/cypress/add-commands", + "@urql/core", + "@urql/devtools", + "@urql/exchange-execute", + "@urql/exchange-graphcache", + "@urql/vue", + "@vue/test-utils", + "@vueuse/core", + "dedent", + "fake-uuid", + "graphql", + "graphql-relay", + "graphql/jsutils/Path", + "gravatar", + "lodash", + "lodash/clone", + "markdown-it", + "@toycode/markdown-it-class", + "path", + "shiki", + "socket.io-client", + "vue", + "vue-router", + "vue-demi", + "vue-i18n", + "vue-toastification", + "vue3-file-selector", + "wonka" + ] + } + } +} diff --git a/packages/launchpad/src/App.vue b/packages/launchpad/src/App.vue new file mode 100644 index 0000000000..310c23d9ac --- /dev/null +++ b/packages/launchpad/src/App.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/packages/launchpad/src/Main.vue b/packages/launchpad/src/Main.vue new file mode 100644 index 0000000000..7727beebd8 --- /dev/null +++ b/packages/launchpad/src/Main.vue @@ -0,0 +1,147 @@ + + + diff --git a/packages/launchpad/src/components/code/FileRow.cy.tsx b/packages/launchpad/src/components/code/FileRow.cy.tsx new file mode 100644 index 0000000000..45918bee51 --- /dev/null +++ b/packages/launchpad/src/components/code/FileRow.cy.tsx @@ -0,0 +1,123 @@ +/* eslint-disable no-irregular-whitespace */ +import FileRow from './FileRow.vue' +import faker from 'faker' +import { defaultMessages } from '@cy/i18n' + +const content = `import { defineConfig } from 'cypress' +import { devServer } from '@cypress/vite-dev-server' + +export default defineConfig({ + component: { + devServer, + devServerConfig: { + entryHtmlFile: 'cypress/component/support/entry.html' + }, + }, +})` + +const description = faker.hacker.phrase() +const messages = defaultMessages.setupPage.configFile + +const changesRequiredDescription = messages.changesRequiredDescription.replace('{0}', '') + +describe('FileRow', () => { + it('renders each status', () => { + cy.mount(() => ( +
+ + + + +
+ )) + + cy.get('pre.shiki').should('exist') + + cy.contains('cypress/integration/support.ts') + cy.contains('cypress/integration/command.js') + cy.contains('cypress.config.js') + cy.contains('cypress/integration/index.js') + + cy.percySnapshot() + }) + + it('opens on click', () => { + cy.mount(() => ( +
+ + +
+ )) + + cy.contains('cypress/integration/command.js') + cy.contains(messages.changesRequiredLabel).should('be.visible') + cy.contains(messages.changesRequiredBadge).should('not.exist') // Hide badge when row is expanded + cy.contains(changesRequiredDescription).should('be.visible') + cy.get('pre').should('have.length', 2) + + cy.percySnapshot('row starts open') + cy.contains('cypress/integration/command.js').click() + + cy.percySnapshot('row collapses after click') + }) + + it('responds nice to small screens', { viewportWidth: 500 }, () => { + const lorem = faker.lorem.paragraphs(3) + + cy.mount(() => ( +
+ +
+ )) + + cy.contains('cypress/integration/command.js') + cy.contains(messages.changesRequiredLabel).should('be.visible') + cy.contains(messages.changesRequiredBadge).should('not.exist') + cy.contains(changesRequiredDescription).should('be.visible') + cy.get('pre').should('exist') + + cy.percySnapshot() + }) +}) diff --git a/packages/launchpad/src/components/code/FileRow.vue b/packages/launchpad/src/components/code/FileRow.vue new file mode 100644 index 0000000000..d4e5ec3c43 --- /dev/null +++ b/packages/launchpad/src/components/code/FileRow.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/packages/launchpad/src/directives/ClickOutside.ts b/packages/launchpad/src/directives/ClickOutside.ts new file mode 100644 index 0000000000..a4e194a10a --- /dev/null +++ b/packages/launchpad/src/directives/ClickOutside.ts @@ -0,0 +1,27 @@ +import type { DirectiveBinding } from 'vue' + +/** + * Runs the binding when clicking outside of the targetted component + */ +export const ClickOutside = { + beforeMount (el: any, binding: DirectiveBinding) { + // Define ourClickEventHandler + const ourClickEventHandler = (event: MouseEvent) => { + if (!el.contains(event.target) && el !== event.target) { + // as we are attaching an click event listern to the document (below) + // ensure the events target is outside the element or a child of it + binding.value(event) // before binding it + } + } + + // attached the handler to the element so we can remove it later easily + el.__vueClickEventHandler__ = ourClickEventHandler + + // attaching ourClickEventHandler to a listener on the document here + document.addEventListener('click', ourClickEventHandler) + }, + unmounted (el: any) { + // Remove Event Listener + document.removeEventListener('click', el.__vueClickEventHandler__) + }, +} diff --git a/packages/launchpad/src/error/BaseError.cy.tsx b/packages/launchpad/src/error/BaseError.cy.tsx new file mode 100644 index 0000000000..fbee593465 --- /dev/null +++ b/packages/launchpad/src/error/BaseError.cy.tsx @@ -0,0 +1,150 @@ +import { codeFrameColumns } from '@babel/code-frame' +import BaseError from './BaseError.vue' +import Button from '@cy/components/Button.vue' +import { BaseErrorFragmentDoc } from '../generated/graphql-test' +import dedent from 'dedent' + +// Selectors +const headerSelector = '[data-testid=error-header]' +const messageSelector = '[data-testid=error-message]' +const retryButtonSelector = '[data-testid=error-retry-button]' +const customFooterSelector = '[data-testid=custom-error-footer]' + +// Constants +const messages = cy.i18n.launchpadErrors.generic +const customHeaderMessage = 'Well, this was unexpected!' +const customMessage = `Don't worry, just click the "It's fixed now" button to try again.` +const customFooterText = `Yikes, try again!` +const customStack = 'some err message\n at fn (foo.js:1:1)' + +describe('', () => { + afterEach(() => { + cy.percySnapshot() + }) + + it('renders the default error the correct messages', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + render: (gqlVal) => , + }) + .get(headerSelector) + .should('contain.text', cy.gqlStub.ErrorWrapper.title) + .get(messageSelector) + .should('contain.text', cy.gqlStub.ErrorWrapper.errorMessage.replace(/\`/g, '').slice(0, 10)) + .get(retryButtonSelector) + .should('not.exist') + }) + + it('renders the retry button if retry is passed', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + render: (gqlVal) => {}} />, + }) + .get(retryButtonSelector) + .should('contain.text', messages.retryButton) + }) + + it('does not open the stack by default if it is not a user error', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + onResult (result) { + result.isUserCodeError = false + }, + render: (gqlVal) => , + }).then(() => { + cy.get('[data-cy=stack-open-true]').should('not.exist') + cy.contains('Stack Trace').click() + cy.contains('Error: foobar').should('be.visible') + cy.get('[data-cy=stack-open-true]') + }) + }) + + it('calls the retry function passed in', () => { + const retrySpy = cy.spy().as('retry') + + cy.mountFragment(BaseErrorFragmentDoc, { + render: (gqlVal) => (
+ , +
), + }) + .get(retryButtonSelector) + .click() + .click() + .get('@retry') + .should('have.been.calledTwice') + }) + + it('renders custom error messages and headers with props', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + onResult: (result) => { + result.title = customHeaderMessage + result.errorMessage = customMessage + result.errorStack = customStack + }, + render: (gqlVal) => (
+ +
), + }) + .get('body') + .should('contain.text', customHeaderMessage) + .and('contain.text', customMessage) + .and('contain.text', customStack) + }) + + it('renders the header, message, and footer slots', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + onResult: (result) => { + result.title = messages.header + result.errorMessage = messages.message + }, + render: (gqlVal) => ( + , + header: () => <>{customHeaderMessage}, + message: () => <>{customMessage} }} + />), + }) + .get('body') + .should('contain.text', customHeaderMessage) + .and('contain.text', customMessage) + .get(customFooterSelector) + .should('contain.text', customFooterText) + }) + + it('renders the header, message, and footer slots', () => { + cy.mountFragment(BaseErrorFragmentDoc, { + onResult: (result) => { + result.title = messages.header + result.codeFrame = { + __typename: 'CodeFrame', + line: 12, + column: 25, + codeBlock: codeFrameColumns(dedent` + const x = 1; + + throw new Error('Some Error'); + + const y = 2; + `, { + start: { + line: 3, + column: 5, + }, + }, { + linesAbove: 2, + linesBelow: 4, + }), + file: { + id: `FileParts:/absolute/full/path/cypress/e2e/file.cy.js`, + __typename: 'FileParts', + relative: 'cypress/e2e/file.cy.js', + absolute: '/absolute/full/path/cypress/e2e/file.cy.js', + }, + } + }, + render: (gqlVal) => ( + ), + }) + + cy.findByText('cypress/e2e/file.cy.js:12:25').should('be.visible') + }) +}) diff --git a/packages/launchpad/src/error/BaseError.vue b/packages/launchpad/src/error/BaseError.vue new file mode 100644 index 0000000000..aa7691e7b8 --- /dev/null +++ b/packages/launchpad/src/error/BaseError.vue @@ -0,0 +1,136 @@ + + + diff --git a/packages/launchpad/src/error/ErrorCodeFrame.vue b/packages/launchpad/src/error/ErrorCodeFrame.vue new file mode 100644 index 0000000000..9f077a8ee8 --- /dev/null +++ b/packages/launchpad/src/error/ErrorCodeFrame.vue @@ -0,0 +1,55 @@ + + + diff --git a/packages/launchpad/src/global/FileDropzone.vue b/packages/launchpad/src/global/FileDropzone.vue new file mode 100644 index 0000000000..f7028fb395 --- /dev/null +++ b/packages/launchpad/src/global/FileDropzone.vue @@ -0,0 +1,110 @@ + + diff --git a/packages/launchpad/src/global/GlobalEmpty.cy.tsx b/packages/launchpad/src/global/GlobalEmpty.cy.tsx new file mode 100644 index 0000000000..dd52e6c85e --- /dev/null +++ b/packages/launchpad/src/global/GlobalEmpty.cy.tsx @@ -0,0 +1,25 @@ +import { defaultMessages } from '@cy/i18n' +import GlobalEmpty from './GlobalEmpty.vue' + +const emptyText = defaultMessages.globalPage.empty + +describe('', () => { + beforeEach(() => { + cy.mount(() => (
+ +
)) + }) + + it('renders the empty state', () => { + cy.contains(emptyText.title) + cy.contains(emptyText.helper) + + const parts = emptyText.dropText.split('{0}') + + cy.contains(parts[0]) + cy.contains(emptyText.browseManually) + + cy.get('input[type=file]').should('have.length', 1) + }) +}) diff --git a/packages/launchpad/src/global/GlobalEmpty.vue b/packages/launchpad/src/global/GlobalEmpty.vue new file mode 100644 index 0000000000..b3b5b026d2 --- /dev/null +++ b/packages/launchpad/src/global/GlobalEmpty.vue @@ -0,0 +1,22 @@ + + + diff --git a/packages/launchpad/src/global/GlobalPage.cy.tsx b/packages/launchpad/src/global/GlobalPage.cy.tsx new file mode 100644 index 0000000000..d70b0f4718 --- /dev/null +++ b/packages/launchpad/src/global/GlobalPage.cy.tsx @@ -0,0 +1,94 @@ +import { defaultMessages } from '@cy/i18n' +import GlobalPage from './GlobalPage.vue' +import type { GlobalPageFragment } from '../generated/graphql-test' +import { GlobalPageFragmentDoc, GlobalPage_AddProjectDocument } from '../generated/graphql-test' + +const searchLabel = defaultMessages.globalPage.searchPlaceholder +const emptyMessages = defaultMessages.globalPage.empty +const testProject = 'some-test-title' +const anotherTestProject = 'another-test-project' +const testProjectPath = '/usr/local/dev/projects/some-test-title' + +describe('', { viewportHeight: 900, viewportWidth: 1200 }, () => { + describe('without projects', () => { + it('renders the empty state', () => { + cy.mount(() => (
+ +
)) + + cy.findByText(emptyMessages.title).should('be.visible') + cy.findByText(emptyMessages.helper).should('be.visible') + + const addProjectStub = cy.stub() + + cy.stubMutationResolver(GlobalPage_AddProjectDocument, (defineResult) => { + addProjectStub() + + return defineResult({ + addProject: { + 'projects': [ + { + 'id': '1', + 'title': 'some-test-title', + 'projectRoot': '/usr/local/dev/projects/some-test-title', + '__typename': 'GlobalProject', + }, + { + 'id': 'R2xvYmFsUHJvamVjdDoyOmFub3RoZXItdGVzdC1wcm9qZWN0', + 'title': 'another-test-project', + 'projectRoot': '/usr/local/dev/projects/another-test-project', + '__typename': 'GlobalProject', + }, + ], + 'localSettings': { + 'availableEditors': [], + 'preferences': { + 'preferredEditorBinary': null, + '__typename': 'LocalSettingsPreferences', + }, + '__typename': 'LocalSettings', + }, + '__typename': 'Query', + } }) + }) + + cy.findByText(emptyMessages.browseManually).click() + + cy.wrap(addProjectStub).should('have.been.called') + }) + }) + + describe('with projects', () => { + beforeEach(() => { + cy.mountFragment(GlobalPageFragmentDoc, { + render: (gqlVal) => , + }) + }) + + it('renders projects', () => { + cy.findByText(testProject).should('be.visible') + cy.findByText(testProjectPath).should('be.visible') + }) + + it('can filter down the projects by name', () => { + cy.findByText(testProject).should('be.visible') + cy.findByLabelText(searchLabel).type(anotherTestProject, { delay: 0 }) + cy.findByText(anotherTestProject).should('be.visible') + cy.findByText(testProject).should('not.exist') + cy.findByLabelText(searchLabel).clear() + cy.findByText(testProject).should('be.visible') + cy.findByText(anotherTestProject).should('be.visible') + }) + + it('can add a project when clicking the button', () => { + cy.findByText('cypress-config-ts').should('not.exist') + + cy.contains('button', defaultMessages.globalPage.addProjectButton).click() + cy.get('input[type=file]') + .attachFileWithPath('absolute/path/to/yet-another-test-project/cypress.config.ts') + .trigger('change', { force: true }) + + cy.findByText('cypress-config-ts').should('be.visible') + }) + }) +}) diff --git a/packages/launchpad/src/global/GlobalPage.vue b/packages/launchpad/src/global/GlobalPage.vue new file mode 100644 index 0000000000..b6b853d8eb --- /dev/null +++ b/packages/launchpad/src/global/GlobalPage.vue @@ -0,0 +1,135 @@ + + + diff --git a/packages/launchpad/src/global/GlobalPageHeader.cy.tsx b/packages/launchpad/src/global/GlobalPageHeader.cy.tsx new file mode 100644 index 0000000000..e9e4246aac --- /dev/null +++ b/packages/launchpad/src/global/GlobalPageHeader.cy.tsx @@ -0,0 +1,53 @@ +import { defaultMessages } from '@cy/i18n' +import GlobalPageHeader from './GlobalPageHeader.vue' +import { ref } from 'vue' + +const searchLabel = defaultMessages.globalPage.searchPlaceholder +const dropzoneSelector = '[data-cy="dropzone"] > div' +const fileInputSelector = 'input[type=file]' +const addProjectSelector = '[data-cy=addProjectButton]' + +describe('', () => { + beforeEach(() => { + const search = ref('') + + cy.wrap(search).as('search') + const fileUploadSpy = cy.spy().as('fileUpload') + + // @ts-ignore = vModel is v-model in vue + cy.mount(() => (
)) + + cy.contains('button', defaultMessages.globalPage.addProjectButton) + .click() + .get(fileInputSelector) + .then(($input) => { + $input.on('change', fileUploadSpy) + }) + }) + + it('renders and has a reactive input', () => { + const searchText = 'My project name goes here' + + cy.findByLabelText(searchLabel) + .type(searchText) + .get('@search').its('value').should('eq', searchText) + }) + + it('should not display the file input', () => { + cy.get(fileInputSelector).should('not.be.visible') + }) + + it('should have webkit attributes', () => { + // These two properties allow us to get the full file path of the file + cy.get(fileInputSelector).should('have.attr', 'webkitdirectory') + .get(fileInputSelector).should('have.attr', 'webkitRelativePath') + }) + + it('handles a file upload', () => { + cy.get(dropzoneSelector) + .selectFile('cypress/fixtures/test-project/cypress.config.ts', { action: 'drag-drop' }) + .get(addProjectSelector) + .click() + .get('@fileUpload').should('have.been.called') + }) +}) diff --git a/packages/launchpad/src/global/GlobalPageHeader.vue b/packages/launchpad/src/global/GlobalPageHeader.vue new file mode 100644 index 0000000000..bd0cf6cd0b --- /dev/null +++ b/packages/launchpad/src/global/GlobalPageHeader.vue @@ -0,0 +1,87 @@ + + + diff --git a/packages/launchpad/src/global/GlobalProjectCard.cy.tsx b/packages/launchpad/src/global/GlobalProjectCard.cy.tsx new file mode 100644 index 0000000000..33513e198b --- /dev/null +++ b/packages/launchpad/src/global/GlobalProjectCard.cy.tsx @@ -0,0 +1,100 @@ +import GlobalProjectCard from './GlobalProjectCard.vue' +import { GlobalProjectCardFragmentDoc } from '../generated/graphql-test' +import { defaultMessages } from '@cy/i18n' + +const defaultPath = '/usr/local/dev/projects/some-test-title' +const menuSelector = '[data-cy=project-card-menu-items]' +const projectCardSelector = '[data-cy=project-card]' + +describe('', () => { + beforeEach(() => { + const removeProjectSpy = cy.spy().as('removeProjectSpy') + const openInFinderSpy = cy.spy().as('openInFinderSpy') + const openInIDESpy = cy.spy().as('openInIDESpy') + const setCurrentProjectSpy = cy.spy().as('setCurrentProjectSpy') + + cy.mountFragment(GlobalProjectCardFragmentDoc, { + render: (gqlValue) => ( +
+ +
+ ), + }) + + cy.findByLabelText(defaultMessages.globalPage.projectActions, { selector: 'button' }) + .as('openMenuButton') + }) + + it('renders', () => { + cy.findByText('some-test-title').should('be.visible') + cy.findByText(defaultPath).should('be.visible') + }) + + describe('Menu', () => { + beforeEach(() => { + cy.get('@openMenuButton') + .click() + }) + + it('emits openInIDE with path value on click', () => { + cy.contains(defaultMessages.globalPage.openInIDE) + .click() + .get('@openInIDESpy') + .should('have.been.calledOnceWith', defaultPath) + .get(menuSelector) + .should('not.exist') + }) + + it('emits openInFinder with path value on click', () => { + cy.contains(defaultMessages.globalPage.openInFinder) + .click() + .get('@openInFinderSpy') + .should('have.been.calledOnceWith', defaultPath) + .get(menuSelector) + .should('not.exist') + }) + + it('emits removeProject with path value on click', () => { + cy.contains(defaultMessages.globalPage.removeProject) + .click() + .get('@removeProjectSpy') + .should('have.been.calledOnceWith', defaultPath) + .get(menuSelector) + .should('not.exist') + }) + + describe('dismiss', () => { + it('opens project when card is clicked on while menu is open', () => { + cy.get(projectCardSelector) + .click() + .get('@setCurrentProjectSpy') + .should('have.been.calledOnceWith', defaultPath) + }) + + it('does not open project when menu button is clicked on while menu is open', () => { + cy.get('@openMenuButton') + .should('be.visible') + .click() + .get('@setCurrentProjectSpy') + .should('not.have.been.called') + }) + + it('dismisses when escape is pressed', () => { + cy.get('body').type('{esc}') + .get(menuSelector) + .should('not.exist') + }) + + it('dismisses when clicking off the menu', () => { + cy.get('body') + .click(0, 0) + .get(menuSelector) + .should('not.exist') + }) + }) + }) +}) diff --git a/packages/launchpad/src/global/GlobalProjectCard.vue b/packages/launchpad/src/global/GlobalProjectCard.vue new file mode 100644 index 0000000000..c9a4ccf0d0 --- /dev/null +++ b/packages/launchpad/src/global/GlobalProjectCard.vue @@ -0,0 +1,141 @@ + + + diff --git a/packages/launchpad/src/images/ct-preview.png b/packages/launchpad/src/images/ct-preview.png new file mode 100644 index 0000000000..9799e726dd Binary files /dev/null and b/packages/launchpad/src/images/ct-preview.png differ diff --git a/packages/launchpad/src/images/e2e-preview.png b/packages/launchpad/src/images/e2e-preview.png new file mode 100644 index 0000000000..448564cd2e Binary files /dev/null and b/packages/launchpad/src/images/e2e-preview.png differ diff --git a/packages/launchpad/src/images/logos/nextjs.svg b/packages/launchpad/src/images/logos/nextjs.svg new file mode 100644 index 0000000000..2ff583328a --- /dev/null +++ b/packages/launchpad/src/images/logos/nextjs.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/launchpad/src/images/logos/nuxt.svg b/packages/launchpad/src/images/logos/nuxt.svg new file mode 100644 index 0000000000..0517b9b66a --- /dev/null +++ b/packages/launchpad/src/images/logos/nuxt.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/launchpad/src/images/logos/react.svg b/packages/launchpad/src/images/logos/react.svg new file mode 100644 index 0000000000..292c3ab3ce --- /dev/null +++ b/packages/launchpad/src/images/logos/react.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/launchpad/src/images/logos/vite.svg b/packages/launchpad/src/images/logos/vite.svg new file mode 100644 index 0000000000..31ef0a0785 --- /dev/null +++ b/packages/launchpad/src/images/logos/vite.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/launchpad/src/images/logos/vue.svg b/packages/launchpad/src/images/logos/vue.svg new file mode 100644 index 0000000000..ea24874dc6 --- /dev/null +++ b/packages/launchpad/src/images/logos/vue.svg @@ -0,0 +1,2 @@ + + diff --git a/packages/launchpad/src/images/logos/webpack.svg b/packages/launchpad/src/images/logos/webpack.svg new file mode 100644 index 0000000000..4115d1049f --- /dev/null +++ b/packages/launchpad/src/images/logos/webpack.svg @@ -0,0 +1 @@ +icon diff --git a/packages/launchpad/src/images/success.svg b/packages/launchpad/src/images/success.svg new file mode 100644 index 0000000000..666b5d0d98 --- /dev/null +++ b/packages/launchpad/src/images/success.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/launchpad/src/main.scss b/packages/launchpad/src/main.scss new file mode 100644 index 0000000000..81a463e5a8 --- /dev/null +++ b/packages/launchpad/src/main.scss @@ -0,0 +1 @@ +@use '@packages/frontend-shared/src/styles/shared.scss'; diff --git a/packages/launchpad/src/main.ts b/packages/launchpad/src/main.ts new file mode 100644 index 0000000000..d177b57629 --- /dev/null +++ b/packages/launchpad/src/main.ts @@ -0,0 +1,39 @@ +import { createApp } from 'vue' +import { HeaderBar_HeaderBarQueryDocument } from './generated/graphql' +import './main.scss' +import 'virtual:windi.css' +import urql from '@urql/vue' +import App from './App.vue' +import Toast, { POSITION } from 'vue-toastification' +import 'vue-toastification/dist/index.css' +import { makeUrqlClient } from '@packages/frontend-shared/src/graphql/urqlClient' +import { createI18n } from '@cy/i18n' +import { initHighlighter } from '@cy/components/ShikiHighlight.vue' + +const app = createApp(App) + +app.use(Toast, { + position: POSITION.BOTTOM_RIGHT, + draggable: false, + closeOnClick: false, +}) + +app.use(createI18n()) + +Promise.all([ + makeUrqlClient({ target: 'launchpad' }).then((launchpadClient) => { + app.use(urql, launchpadClient) + + // Loading the Header Bar Query document prior to mounting leads to a better experience + // when doing things like taking snapshots of the DOM during testing, and it + // shouldn't be any different to the user + launchpadClient + .query(HeaderBar_HeaderBarQueryDocument) + .toPromise() + }), + // Make sure highlighter is initialized immediately at app + // start, so it's available when we render code blocks + initHighlighter(), +]).then(() => { + app.mount('#app') +}) diff --git a/packages/launchpad/src/migration/ConvertConfigFile.cy.tsx b/packages/launchpad/src/migration/ConvertConfigFile.cy.tsx new file mode 100644 index 0000000000..e05bbf041d --- /dev/null +++ b/packages/launchpad/src/migration/ConvertConfigFile.cy.tsx @@ -0,0 +1,112 @@ +import { defaultMessages } from '@cy/i18n' +import { ConvertConfigFileFragmentDoc } from '../generated/graphql-test' +import ConvertConfigFile from './ConvertConfigFile.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders the lines for components folder', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + onResult (res) { + res.hasCustomComponentFolder = true + + return res + }, + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText('component.specPattern').should('be.visible') + cy.findByText('componentFolder').should('be.visible') + }) + + it('renders the lines for components testFiles', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + onResult (res) { + res.hasCustomComponentTestFiles = true + + return res + }, + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText('component.specPattern').should('be.visible') + cy.findByText('testFiles').should('be.visible') + cy.findByText('e2e.specPattern').should('not.exist') + }) + + it('renders the lines for e2e folder', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + onResult (res) { + res.hasCustomIntegrationFolder = true + + return res + }, + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText('e2e.specPattern').should('be.visible') + cy.findByText('integrationFolder').should('be.visible') + }) + + it('renders the lines for e2e testFiles', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + onResult (res) { + res.hasCustomIntegrationTestFiles = true + + return res + }, + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText('e2e.specPattern').should('be.visible') + cy.findByText('testFiles').should('be.visible') + cy.findByText('componentFolder').should('not.exist') + }) + + it('renders all lines if both are custom', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + onResult (res) { + res.hasCustomIntegrationTestFiles = true + res.hasCustomComponentFolder = true + + return res + }, + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText('e2e.specPattern').should('be.visible') + cy.findByText('component.specPattern').should('be.visible') + cy.contains('li', 'testFiles').should('contain', 'e2e.specPattern') + cy.contains('li', 'componentFolder').should('contain', 'component.specPattern') + }) + + it('renders expected content with title', () => { + cy.mountFragment(ConvertConfigFileFragmentDoc, { + render (gql) { + return (
+ +
) + }, + }) + + cy.contains(defaultMessages.migration.configFile.title).should('be.visible') + }) +}) diff --git a/packages/launchpad/src/migration/ConvertConfigFile.vue b/packages/launchpad/src/migration/ConvertConfigFile.vue new file mode 100644 index 0000000000..963aa9c1a9 --- /dev/null +++ b/packages/launchpad/src/migration/ConvertConfigFile.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/packages/launchpad/src/migration/MigrationWizard.vue b/packages/launchpad/src/migration/MigrationWizard.vue new file mode 100644 index 0000000000..c3e20de961 --- /dev/null +++ b/packages/launchpad/src/migration/MigrationWizard.vue @@ -0,0 +1,400 @@ + + + diff --git a/packages/launchpad/src/migration/OptOutModalStep1.cy.tsx b/packages/launchpad/src/migration/OptOutModalStep1.cy.tsx new file mode 100644 index 0000000000..68ac712a39 --- /dev/null +++ b/packages/launchpad/src/migration/OptOutModalStep1.cy.tsx @@ -0,0 +1,7 @@ +import OptOutModalStep1 from './OptOutModalStep1.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mount(OptOutModalStep1) + }) +}) diff --git a/packages/launchpad/src/migration/OptOutModalStep1.vue b/packages/launchpad/src/migration/OptOutModalStep1.vue new file mode 100644 index 0000000000..85d3f4f95e --- /dev/null +++ b/packages/launchpad/src/migration/OptOutModalStep1.vue @@ -0,0 +1,97 @@ + + + diff --git a/packages/launchpad/src/migration/OptOutModalStep2.cy.tsx b/packages/launchpad/src/migration/OptOutModalStep2.cy.tsx new file mode 100644 index 0000000000..8d198c6ebc --- /dev/null +++ b/packages/launchpad/src/migration/OptOutModalStep2.cy.tsx @@ -0,0 +1,7 @@ +import OptOutModalStep2 from './OptOutModalStep2.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mount(OptOutModalStep2) + }) +}) diff --git a/packages/launchpad/src/migration/OptOutModalStep2.vue b/packages/launchpad/src/migration/OptOutModalStep2.vue new file mode 100644 index 0000000000..5448625fe5 --- /dev/null +++ b/packages/launchpad/src/migration/OptOutModalStep2.vue @@ -0,0 +1,93 @@ + + + diff --git a/packages/launchpad/src/migration/RenameSpecsAuto.cy.tsx b/packages/launchpad/src/migration/RenameSpecsAuto.cy.tsx new file mode 100644 index 0000000000..2f78fb03c9 --- /dev/null +++ b/packages/launchpad/src/migration/RenameSpecsAuto.cy.tsx @@ -0,0 +1,46 @@ +import { defaultMessages } from '@cy/i18n' +import { RenameSpecsAutoFragmentDoc } from '../generated/graphql-test' +import RenameSpecsAuto from './RenameSpecsAuto.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders the title', () => { + cy.mountFragment(RenameSpecsAutoFragmentDoc, { + render (gql) { + return (
+ +
) + }, + }) + + cy.contains(defaultMessages.migration.renameAuto.title).should('be.visible') + }) + + it('renders the change link', () => { + cy.mountFragment(RenameSpecsAutoFragmentDoc, { + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText(defaultMessages.migration.renameAuto.changeButton).should('be.visible') + }) + + it('changes the skip status when proceeding to change', () => { + cy.mountFragment(RenameSpecsAutoFragmentDoc, { + render (gql) { + return (
+ +
) + }, + }) + + cy.findByText(defaultMessages.migration.renameAuto.optedOutMessage).should('not.exist') + cy.findByText(defaultMessages.migration.renameAuto.changeButton).click() + cy.findByText(defaultMessages.migration.renameAuto.modals.step1.buttonProceed).click() + cy.findByText(defaultMessages.migration.renameAuto.modals.step2.option3).click() + cy.findByText(defaultMessages.migration.renameAuto.modals.step2.buttonSave).click() + cy.findByText(defaultMessages.migration.renameAuto.folderRenameMessage).should('be.visible') + }) +}) diff --git a/packages/launchpad/src/migration/RenameSpecsAuto.vue b/packages/launchpad/src/migration/RenameSpecsAuto.vue new file mode 100644 index 0000000000..a49c276288 --- /dev/null +++ b/packages/launchpad/src/migration/RenameSpecsAuto.vue @@ -0,0 +1,147 @@ + + + diff --git a/packages/launchpad/src/migration/RenameSpecsManual.cy.tsx b/packages/launchpad/src/migration/RenameSpecsManual.cy.tsx new file mode 100644 index 0000000000..14fb9d870d --- /dev/null +++ b/packages/launchpad/src/migration/RenameSpecsManual.cy.tsx @@ -0,0 +1,16 @@ +import { RenameSpecsManualFragmentDoc } from '../generated/graphql-test' +import RenameSpecsManual from './RenameSpecsManual.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mountFragment(RenameSpecsManualFragmentDoc, { + render (gql) { + return ( +
+ +
+ ) + }, + }) + }) +}) diff --git a/packages/launchpad/src/migration/RenameSpecsManual.vue b/packages/launchpad/src/migration/RenameSpecsManual.vue new file mode 100644 index 0000000000..837b94375a --- /dev/null +++ b/packages/launchpad/src/migration/RenameSpecsManual.vue @@ -0,0 +1,116 @@ + + + diff --git a/packages/launchpad/src/migration/RenameSupport.cy.tsx b/packages/launchpad/src/migration/RenameSupport.cy.tsx new file mode 100644 index 0000000000..9de8a0ad6f --- /dev/null +++ b/packages/launchpad/src/migration/RenameSupport.cy.tsx @@ -0,0 +1,14 @@ +import { RenameSupportFragmentDoc } from '../generated/graphql-test' +import RenameSupport from './RenameSupport.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mountFragment(RenameSupportFragmentDoc, { + render (gql) { + return (
+ +
) + }, + }) + }) +}) diff --git a/packages/launchpad/src/migration/RenameSupport.vue b/packages/launchpad/src/migration/RenameSupport.vue new file mode 100644 index 0000000000..fe9411dfdc --- /dev/null +++ b/packages/launchpad/src/migration/RenameSupport.vue @@ -0,0 +1,72 @@ + + + diff --git a/packages/launchpad/src/migration/SetupComponentTesting.cy.tsx b/packages/launchpad/src/migration/SetupComponentTesting.cy.tsx new file mode 100644 index 0000000000..06ad414904 --- /dev/null +++ b/packages/launchpad/src/migration/SetupComponentTesting.cy.tsx @@ -0,0 +1,9 @@ +import SetupComponentTesting from './SetupComponentTesting.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mount(() => (
+ +
)) + }) +}) diff --git a/packages/launchpad/src/migration/SetupComponentTesting.vue b/packages/launchpad/src/migration/SetupComponentTesting.vue new file mode 100644 index 0000000000..a246d37e3b --- /dev/null +++ b/packages/launchpad/src/migration/SetupComponentTesting.vue @@ -0,0 +1,29 @@ + + + diff --git a/packages/launchpad/src/migration/fragments/BeforeAfter.cy.tsx b/packages/launchpad/src/migration/fragments/BeforeAfter.cy.tsx new file mode 100644 index 0000000000..3383940495 --- /dev/null +++ b/packages/launchpad/src/migration/fragments/BeforeAfter.cy.tsx @@ -0,0 +1,12 @@ +import BeforeAfter from './BeforeAfter.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + cy.mount(() => (
+
b-content
, + after: () =>
a-content
, + }} /> +
)) + }) +}) diff --git a/packages/launchpad/src/migration/fragments/BeforeAfter.vue b/packages/launchpad/src/migration/fragments/BeforeAfter.vue new file mode 100644 index 0000000000..d51bf12a68 --- /dev/null +++ b/packages/launchpad/src/migration/fragments/BeforeAfter.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/launchpad/src/migration/fragments/HighlightedFile.cy.tsx b/packages/launchpad/src/migration/fragments/HighlightedFile.cy.tsx new file mode 100644 index 0000000000..ee2094aa7e --- /dev/null +++ b/packages/launchpad/src/migration/fragments/HighlightedFile.cy.tsx @@ -0,0 +1,29 @@ +import type { FilePart } from '@packages/data-context/src/sources/migration' +import HighlightedFile from './HighlightedFile.vue' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + const part: readonly FilePart[] = [ + { + highlight: false, + text: 'cypress/', + }, + { + highlight: true, + group: 'folder', + text: 'integration', + }, + { + highlight: false, + text: '/foo.spec.js', + }, + ] + + cy.mount(() => (
+ +
)) + }) +}) diff --git a/packages/launchpad/src/migration/fragments/HighlightedFile.vue b/packages/launchpad/src/migration/fragments/HighlightedFile.vue new file mode 100644 index 0000000000..ab4b23622d --- /dev/null +++ b/packages/launchpad/src/migration/fragments/HighlightedFile.vue @@ -0,0 +1,29 @@ + + + diff --git a/packages/launchpad/src/migration/fragments/HighlightedFilesList.cy.tsx b/packages/launchpad/src/migration/fragments/HighlightedFilesList.cy.tsx new file mode 100644 index 0000000000..06110d3b47 --- /dev/null +++ b/packages/launchpad/src/migration/fragments/HighlightedFilesList.cy.tsx @@ -0,0 +1,33 @@ +import HighlightedFilesList from './HighlightedFilesList.vue' +import type { FilePart } from '@packages/data-context/src/sources/migration' + +describe('', { viewportWidth: 1119 }, () => { + it('renders expected content', () => { + type PropType = Readonly> + + const parts: readonly FilePart[] = [ + { + highlight: false, + text: 'cypress/', + }, + { + highlight: true, + group: 'folder', + text: 'integration', + }, + { + highlight: false, + text: '/foo.spec.js', + }, + ] + + const files: PropType = [{ parts }] + + cy.mount(() => (
+ +
)) + }) +}) diff --git a/packages/launchpad/src/migration/fragments/HighlightedFilesList.vue b/packages/launchpad/src/migration/fragments/HighlightedFilesList.vue new file mode 100644 index 0000000000..d4768517ec --- /dev/null +++ b/packages/launchpad/src/migration/fragments/HighlightedFilesList.vue @@ -0,0 +1,28 @@ + + + diff --git a/packages/launchpad/src/migration/fragments/MigrationList.vue b/packages/launchpad/src/migration/fragments/MigrationList.vue new file mode 100644 index 0000000000..047ab3c7be --- /dev/null +++ b/packages/launchpad/src/migration/fragments/MigrationList.vue @@ -0,0 +1,5 @@ + diff --git a/packages/launchpad/src/migration/fragments/MigrationListItem.vue b/packages/launchpad/src/migration/fragments/MigrationListItem.vue new file mode 100644 index 0000000000..a291d56594 --- /dev/null +++ b/packages/launchpad/src/migration/fragments/MigrationListItem.vue @@ -0,0 +1,7 @@ + diff --git a/packages/launchpad/src/migration/fragments/MigrationStep.vue b/packages/launchpad/src/migration/fragments/MigrationStep.vue new file mode 100644 index 0000000000..f840b30ebc --- /dev/null +++ b/packages/launchpad/src/migration/fragments/MigrationStep.vue @@ -0,0 +1,74 @@ + + + diff --git a/packages/launchpad/src/migration/fragments/MigrationTitle.vue b/packages/launchpad/src/migration/fragments/MigrationTitle.vue new file mode 100644 index 0000000000..0e844846c9 --- /dev/null +++ b/packages/launchpad/src/migration/fragments/MigrationTitle.vue @@ -0,0 +1,15 @@ + + + diff --git a/packages/launchpad/src/migration/types.ts b/packages/launchpad/src/migration/types.ts new file mode 100644 index 0000000000..2eec99a9e7 --- /dev/null +++ b/packages/launchpad/src/migration/types.ts @@ -0,0 +1 @@ +export type PossibleOption = 'rename' | 'renameFolder' | 'skip' diff --git a/packages/launchpad/src/setup/ButtonBar.cy.tsx b/packages/launchpad/src/setup/ButtonBar.cy.tsx new file mode 100644 index 0000000000..c7961f809b --- /dev/null +++ b/packages/launchpad/src/setup/ButtonBar.cy.tsx @@ -0,0 +1,60 @@ +import ButtonBar from './ButtonBar.vue' +import { defaultMessages } from '@cy/i18n' + +const { next: nextLabel, back: backLabel } = defaultMessages.setupPage.step + +describe('', () => { + let nextFn: ReturnType + let backFn: ReturnType + + beforeEach(() => { + nextFn = cy.stub() + backFn = cy.stub() + }) + + it('playground', () => { + cy.mount(() => ) + }) + + it('should trigger the next function', () => { + cy.mount(() => ) + cy.contains(nextLabel) + .click() + .then(() => { + expect(nextFn).to.have.been.calledOnce + }) + }) + + it('should trigger the back function', () => { + cy.mount(() => ) + cy.contains(backLabel) + .click() + .then(() => { + expect(backFn).to.have.been.calledOnce + }) + }) + + it('should show a switch on the right when alt is mentionned and onAlt is set', () => { + const altFunction = cy.spy() + + cy.mount(() => ( + + )) + + cy.findAllByLabelText('Install manually') + .click() + .then(() => { + expect(altFunction).to.have.been.calledOnce + }) + }) + + it('changes the main button variant', () => { + const altFunction = cy.spy() + + cy.mount(() => ( + + )) + + cy.contains('button', 'Waiting for you').find('svg').should('be.visible') + }) +}) diff --git a/packages/launchpad/src/setup/ButtonBar.vue b/packages/launchpad/src/setup/ButtonBar.vue new file mode 100644 index 0000000000..d1895f5d70 --- /dev/null +++ b/packages/launchpad/src/setup/ButtonBar.vue @@ -0,0 +1,98 @@ + + + diff --git a/packages/launchpad/src/setup/CompareTestingCard.vue b/packages/launchpad/src/setup/CompareTestingCard.vue new file mode 100644 index 0000000000..7a40d3bb96 --- /dev/null +++ b/packages/launchpad/src/setup/CompareTestingCard.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/launchpad/src/setup/CompareTestingTypes.cy.tsx b/packages/launchpad/src/setup/CompareTestingTypes.cy.tsx new file mode 100644 index 0000000000..e52d470f79 --- /dev/null +++ b/packages/launchpad/src/setup/CompareTestingTypes.cy.tsx @@ -0,0 +1,10 @@ +import CompareTestingTypes from './CompareTestingTypes.vue' +import { defaultMessages } from '@cy/i18n' + +describe('TestingTypeCards', () => { + it('renders expected content', () => { + cy.mount(CompareTestingTypes) + Object.values(defaultMessages.welcomePage.compareTypes.content).forEach((pieceOfText) => + cy.contains(pieceOfText).should('be.visible')) + }) +}) diff --git a/packages/launchpad/src/setup/CompareTestingTypes.vue b/packages/launchpad/src/setup/CompareTestingTypes.vue new file mode 100644 index 0000000000..f07b6aa7b8 --- /dev/null +++ b/packages/launchpad/src/setup/CompareTestingTypes.vue @@ -0,0 +1,67 @@ + + + diff --git a/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx b/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx new file mode 100644 index 0000000000..86954f1843 --- /dev/null +++ b/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx @@ -0,0 +1,100 @@ +import { EnvironmentSetupFragmentDoc } from '../generated/graphql-test' +import EnvironmentSetup from './EnvironmentSetup.vue' +import { CODE_LANGUAGES } from '../../../types/src/constants' +import { FRONTEND_FRAMEWORKS } from '@packages/scaffold-config' + +describe('', { viewportWidth: 800 }, () => { + it('default component', () => { + cy.mountFragment(EnvironmentSetupFragmentDoc, { + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.findByRole('button', { + name: 'Front-end Framework Pick a framework', + expanded: false, + }) + .should('have.attr', 'aria-haspopup', 'true') + .click() + .should('have.attr', 'aria-expanded', 'true') + + const frameworkIconName = (frameworkName) => { + if (frameworkName.includes('React')) { + return 'react-logo' + } + + if (frameworkName.includes('Nuxt')) { + return 'nuxtjs-logo' + } + + if (frameworkName.includes('Vue')) { + return 'vue-logo' + } + + return `${Cypress._.lowerCase(frameworkName).replace(' ', '')}-logo` + } + + FRONTEND_FRAMEWORKS.forEach((framework) => { + cy.findByRole('option', { name: framework.name }) + .find('svg') + .should('have.attr', 'data-cy', frameworkIconName(framework.name)) + }) + + CODE_LANGUAGES.forEach((lang) => { + cy.findByRole('button', { name: lang.name }) + }) + + cy.findByRole('button', { name: 'Next Step' }) + .should('have.disabled') + }) + + it('renders the detected flag', () => { + cy.mountFragment(EnvironmentSetupFragmentDoc, { + onResult: (res) => { + res.frameworks[0].isDetected = true + }, + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.findByRole('button', { + name: 'Front-end Framework Pick a framework', + expanded: false, + }).click() + + cy.findByRole('option', { name: 'Create React App (v4) (detected)' }).should('be.visible') + }) + + it('shows the description of bundler as Dev Server', () => { + cy.mountFragment(EnvironmentSetupFragmentDoc, { + onResult: (res) => { + res.framework = { + ...res.frameworks[3], + supportedBundlers: res.allBundlers, + } + }, + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.findByLabelText('Bundler(Dev Server)').should('be.visible') + }) +}) diff --git a/packages/launchpad/src/setup/EnvironmentSetup.vue b/packages/launchpad/src/setup/EnvironmentSetup.vue new file mode 100644 index 0000000000..b6c50bf6c4 --- /dev/null +++ b/packages/launchpad/src/setup/EnvironmentSetup.vue @@ -0,0 +1,185 @@ + + + diff --git a/packages/launchpad/src/setup/InstallDependencies.cy.tsx b/packages/launchpad/src/setup/InstallDependencies.cy.tsx new file mode 100644 index 0000000000..b8009d5d9a --- /dev/null +++ b/packages/launchpad/src/setup/InstallDependencies.cy.tsx @@ -0,0 +1,50 @@ +import { defaultMessages } from '@cy/i18n' +import InstallDependencies from './InstallDependencies.vue' +import { InstallDependenciesFragmentDoc } from '../generated/graphql-test' +import { CYPRESS_REACT_LATEST, CYPRESS_WEBPACK } from '@packages/scaffold-config' + +describe('', () => { + beforeEach(function () { + cy.clock() + this.onBack = cy.spy() + + cy.mountFragment(InstallDependenciesFragmentDoc, { + render: (gqlVal) => { + return + }, + }) + }) + + it('displays package information and links', () => { + cy.contains('a', '@cypress/react') + .should('be.visible') + .and('have.attr', 'href', 'https://www.npmjs.com/package/@cypress/react') + + cy.contains('a', '@cypress/webpack-dev-server') + .should('be.visible') + .and('have.attr', 'href', 'https://www.npmjs.com/package/@cypress/webpack-dev-server') + + cy.contains(CYPRESS_REACT_LATEST.description.split(' { + cy.contains('button', defaultMessages.clipboard.copy).should('be.visible') + cy.contains('button', defaultMessages.setupPage.step.back).should('be.visible') + + cy.contains('button', defaultMessages.setupPage.step.skip).should('be.visible') + }) + + it('triggers back button callback', function () { + cy.findByRole('button', { + name: defaultMessages.setupPage.step.back, + }) + .should('be.visible') + .click() + .then(() => { + expect(this.onBack).to.have.been.calledOnce + }) + }) +}) diff --git a/packages/launchpad/src/setup/InstallDependencies.vue b/packages/launchpad/src/setup/InstallDependencies.vue new file mode 100644 index 0000000000..dd680563ea --- /dev/null +++ b/packages/launchpad/src/setup/InstallDependencies.vue @@ -0,0 +1,106 @@ + + + diff --git a/packages/launchpad/src/setup/LaunchpadHeader.vue b/packages/launchpad/src/setup/LaunchpadHeader.vue new file mode 100644 index 0000000000..46375cc64d --- /dev/null +++ b/packages/launchpad/src/setup/LaunchpadHeader.vue @@ -0,0 +1,16 @@ + + + diff --git a/packages/launchpad/src/setup/ManualInstall.cy.tsx b/packages/launchpad/src/setup/ManualInstall.cy.tsx new file mode 100644 index 0000000000..da06bf7ecd --- /dev/null +++ b/packages/launchpad/src/setup/ManualInstall.cy.tsx @@ -0,0 +1,70 @@ +import sinon from 'sinon' +import { ManualInstallFragmentDoc } from '../generated/graphql-test' +import ManualInstall from './ManualInstall.vue' +import { CYPRESS_REACT_LATEST, CYPRESS_WEBPACK } from '@packages/scaffold-config' +import { Clipboard_CopyToClipboardDocument } from '../generated/graphql' + +describe('', () => { + it('playground', () => { + cy.mountFragment(ManualInstallFragmentDoc, { + render: (gqlVal) => ( +
+ +
+ ), + }) + }) + + it('lists packages and can copy install command to clipboard', { viewportWidth: 800, viewportHeight: 600 }, () => { + const framework = CYPRESS_REACT_LATEST + const bundler = CYPRESS_WEBPACK + + const stubCopy = sinon.stub() + + cy.mountFragment(ManualInstallFragmentDoc, { + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.stubMutationResolver(Clipboard_CopyToClipboardDocument, (defineResult, { text }) => { + stubCopy(text) + + return defineResult({ + copyTextToClipboard: true, + }) + }) + + const installCommand = `npm install -D @cypress/react @cypress/webpack-dev-server` + + cy.findByText(installCommand).should('be.visible') + cy.findByRole('button', { name: 'Copy' }).click() + cy.findByRole('button', { name: 'Copied!' }).should('be.visible') + + cy.wrap(stubCopy).should('have.been.calledWith', installCommand) + + const validatePackage = (packageName: string) => { + cy.findByRole('link', { name: packageName }) + .should('have.attr', 'href', `https://www.npmjs.com/package/${packageName}`) + + cy.contains(framework.description.split(' { + cy.mountFragment(ManualInstallFragmentDoc, { + render: (gqlVal) => ( +
+ +
+ ), + }) + + cy.findByLabelText('installed').should('be.visible') + }) +}) diff --git a/packages/launchpad/src/setup/ManualInstall.vue b/packages/launchpad/src/setup/ManualInstall.vue new file mode 100644 index 0000000000..3a19ef7474 --- /dev/null +++ b/packages/launchpad/src/setup/ManualInstall.vue @@ -0,0 +1,75 @@ + + + diff --git a/packages/launchpad/src/setup/OpenBrowser.vue b/packages/launchpad/src/setup/OpenBrowser.vue new file mode 100644 index 0000000000..672033c6c5 --- /dev/null +++ b/packages/launchpad/src/setup/OpenBrowser.vue @@ -0,0 +1,133 @@ + + + diff --git a/packages/launchpad/src/setup/OpenBrowserList.cy.tsx b/packages/launchpad/src/setup/OpenBrowserList.cy.tsx new file mode 100644 index 0000000000..7b8c2d6a7c --- /dev/null +++ b/packages/launchpad/src/setup/OpenBrowserList.cy.tsx @@ -0,0 +1,152 @@ +import { OpenBrowserListFragmentDoc } from '../generated/graphql-test' +import OpenBrowserList from './OpenBrowserList.vue' +import { longBrowsersList } from '@packages/frontend-shared/cypress/support/mock-graphql/longBrowsersList' +import { defaultMessages } from '@cy/i18n' + +// Testing Note: because state for this component is maintained on the server and updated via gql mutations, +// this component test can't do interactions that change the chosen browser at the moment. Interactions and states +// are covered in the choose-a-browser.cy.ts e2e tests. + +describe('', () => { + beforeEach(() => { + cy.viewport(1000, 750) + }) + + it('renders a long list of found browsers correctly', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + render: (gqlVal) => + (
+ +
), + }) + + longBrowsersList.forEach((browser) => { + cy.contains('label', browser.displayName).should('be.visible') + }) + + // Firefox early version should be disabled + cy.get('[data-cy-browser="firefox"]').should('have.attr', 'aria-disabled', 'true') + cy.get('[data-cy-browser="firefox"] [data-cy="unsupported-browser-tooltip-trigger"]').should('exist') + cy.get('[data-cy-browser="electron"] [data-cy="unsupported-browser-tooltip-trigger"]').should('not.exist') + + // Renders a default logo if we don't provide one + cy.get('[data-cy-browser="fake"]').should('have.attr', 'aria-disabled', 'true') + cy.get('[data-cy-browser="fake"] img').should('have.attr', 'src').should('include', 'generic-browser') + + cy.percySnapshot() + }) + + it('displays a tooltip for an unsupported browser', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + render: (gqlVal) => + (
+
+ +
), + }) + + cy.get('[data-cy-browser="firefox"]:nth(2) [data-cy="unsupported-browser-tooltip"]') + .trigger('mouseenter') + .contains('Cypress does not support running Firefox Developer Edition version 69.') + + cy.percySnapshot() + }) + + it('emits navigates back', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + render: (gqlVal) => ( +
+ +
), + }) + + cy.contains('button', 'Switch testing type').click() + cy.get('@navigatedBack').should('have.been.called') + }) + + it('shows browser is opening', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + onResult: (res) => { + res.browserStatus = 'opening' + }, + render: (gqlVal) => ( +
+ +
), + }) + + cy.get('[data-cy-browser]').each((browser) => cy.wrap(browser).should('have.attr', 'aria-disabled', 'true')) + cy.get('[data-cy="launch-button"]').should('not.exist') + cy.contains('button', defaultMessages.openBrowser.openingE2E.replace('{browser}', 'Electron')).should('be.disabled') + + cy.percySnapshot() + }) + + it('shows browser is open', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + onResult: (res) => { + res.browserStatus = 'open' + }, + render: (gqlVal) => ( +
+ +
), + }) + + cy.get('[data-cy-browser]').each((browser) => cy.wrap(browser).should('have.attr', 'aria-disabled', 'true')) + cy.contains('button', defaultMessages.openBrowser.running.replace('{browser}', 'Electron')).should('be.disabled') + cy.contains('button', defaultMessages.openBrowser.focus) + cy.contains('button', defaultMessages.openBrowser.close).click() + cy.get('@closeBrowser').should('have.been.called') + + cy.percySnapshot() + }) + + it('hides focus button when unsupported', () => { + cy.mountFragment(OpenBrowserListFragmentDoc, { + onResult: (res) => { + res.browserStatus = 'open' + res.activeBrowser!.isFocusSupported = false + }, + render: (gqlVal) => { + return ( +
+ +
) + }, + }) + + cy.contains('button', defaultMessages.openBrowser.running.replace('{browser}', 'Electron')).should('be.disabled') + cy.contains('button', defaultMessages.openBrowser.focus).should('not.exist') + + cy.percySnapshot() + }) + + it('throws when activeBrowser is null', (done) => { + cy.once('uncaught:exception', (err) => { + expect(err.message).to.include('Missing activeBrowser in selectedBrowserId') + done() + }) + + cy.mountFragment(OpenBrowserListFragmentDoc, { + onResult: (res) => { + res.activeBrowser = null + }, + render: (gqlVal) => { + return ( +
+ +
) + }, + }) + }) +}) diff --git a/packages/launchpad/src/setup/OpenBrowserList.vue b/packages/launchpad/src/setup/OpenBrowserList.vue new file mode 100644 index 0000000000..a74ed66bca --- /dev/null +++ b/packages/launchpad/src/setup/OpenBrowserList.vue @@ -0,0 +1,292 @@ + + + diff --git a/packages/launchpad/src/setup/ScaffoldLanguageSelect.vue b/packages/launchpad/src/setup/ScaffoldLanguageSelect.vue new file mode 100644 index 0000000000..356e669bbc --- /dev/null +++ b/packages/launchpad/src/setup/ScaffoldLanguageSelect.vue @@ -0,0 +1,125 @@ + + + diff --git a/packages/launchpad/src/setup/ScaffoldedFiles.cy.tsx b/packages/launchpad/src/setup/ScaffoldedFiles.cy.tsx new file mode 100644 index 0000000000..9366a8481d --- /dev/null +++ b/packages/launchpad/src/setup/ScaffoldedFiles.cy.tsx @@ -0,0 +1,22 @@ +import { + ScaffoldedFilesFragmentDoc, +} from '../generated/graphql-test' +import ScaffoldedFiles from './ScaffoldedFiles.vue' + +describe('', () => { + beforeEach(() => { + cy.mountFragment(ScaffoldedFilesFragmentDoc, { + render: (gql) => { + return ( +
+ +
+ ) + }, + }) + }) + + it('playground', () => { + cy.contains('button', 'Continue').should('exist') + }) +}) diff --git a/packages/launchpad/src/setup/ScaffoldedFiles.vue b/packages/launchpad/src/setup/ScaffoldedFiles.vue new file mode 100644 index 0000000000..ae72e627ec --- /dev/null +++ b/packages/launchpad/src/setup/ScaffoldedFiles.vue @@ -0,0 +1,87 @@ + + + diff --git a/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx b/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx new file mode 100644 index 0000000000..8f71c355b5 --- /dev/null +++ b/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx @@ -0,0 +1,117 @@ +import { ref } from 'vue' +import SelectFwOrBundler, { Option } from './SelectFwOrBundler.vue' + +const manyOptions: Readonly = [ + { + name: 'Vue.js', + id: 'vue', + isSelected: false, + type: 'vue2', + isDetected: true, + }, + { + name: 'React.js', + description: '(detected)', + id: 'react', + isSelected: false, + type: 'react', + }, +] as const + +describe('', () => { + it('playground', () => { + cy.mount(() => ( +
+ +
+ )) + + cy.contains('button', 'React.js').click() + }) + + it('renders the name', () => { + cy.mount(() => ) + + cy.contains('Front-end Framework').should('exist') + }) + + it('shows detected flag', () => { + cy.mount(() => ()) + + cy.contains('React.js').click() + cy.contains('li', 'Vue.js').contains('(detected)').should('be.visible') + }) + + it('shows a placeholder when no value is specified', () => { + cy.mount(() => ( + + )) + + cy.contains('button', 'placeholder').should('exist') + }) + + it('should select the value', () => { + cy.mount(() => ( + + )) + + cy.contains('button', 'React.js').should('exist') + }) + + it('should select the clicked item', () => { + let val = ref('react') + + cy.mount(() => ( + { + val.value = newVal + }} + /> + )) + + cy.contains('button', 'React.js').click() + cy.contains('Vue.js').click() + cy.contains('React.js').should('not.exist') + }) + + it('should close when clicking on the body', () => { + cy.mount(() => ( +
+
click out
+ +
+ )) + + cy.contains('button', 'Vue.js').click() + cy.contains('React.js').should('be.visible') + cy.contains('click out').click() + cy.contains('React.js').should('not.exist') + }) +}) diff --git a/packages/launchpad/src/setup/SelectFwOrBundler.vue b/packages/launchpad/src/setup/SelectFwOrBundler.vue new file mode 100644 index 0000000000..3331860137 --- /dev/null +++ b/packages/launchpad/src/setup/SelectFwOrBundler.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/packages/launchpad/src/setup/SelectLanguage.cy.tsx b/packages/launchpad/src/setup/SelectLanguage.cy.tsx new file mode 100644 index 0000000000..e5b5c72f89 --- /dev/null +++ b/packages/launchpad/src/setup/SelectLanguage.cy.tsx @@ -0,0 +1,56 @@ +import { ref } from 'vue' +import Select from './SelectLanguage.vue' + +const manyOptions = [ + { + id: 'js', + name: 'JavaScript', + isSelected: true, + type: 'js', + }, + { + id: 'ts', + name: 'TypeScript', + isSelected: false, + type: 'ts', + }, +] + +describe('', () => { + it('playground', () => { + cy.mount(() => ( +
+ { + val.value = newVal + }} + /> +
+ )) + + cy.contains('Button', 'TypeScript').click().then(() => { + expect(val.value).to.equal('ts') + }) + }) +}) diff --git a/packages/launchpad/src/setup/SelectLanguage.vue b/packages/launchpad/src/setup/SelectLanguage.vue new file mode 100644 index 0000000000..5700009bf7 --- /dev/null +++ b/packages/launchpad/src/setup/SelectLanguage.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/launchpad/src/setup/TestingTypeCards.cy.tsx b/packages/launchpad/src/setup/TestingTypeCards.cy.tsx new file mode 100644 index 0000000000..304432da36 --- /dev/null +++ b/packages/launchpad/src/setup/TestingTypeCards.cy.tsx @@ -0,0 +1,85 @@ +import { + TestingTypeCardsFragmentDoc, +} from '../generated/graphql-test' +import TestingTypeCards from './TestingTypeCards.vue' +import { defaultMessages } from '@cy/i18n' + +describe('TestingTypeCards', () => { + it('renders correct label when no testingType has been configured', () => { + cy.mountFragment(TestingTypeCardsFragmentDoc, { + onResult: (result, ctx) => { + if (result.currentProject) { + result.currentProject.isCTConfigured = false + result.currentProject.isE2EConfigured = false + result.currentProject.currentTestingType = null + } + }, + render: (gqlVal) => { + return + }, + }).then(() => { + cy.findAllByText(defaultMessages.setupPage.testingCard.notConfigured).should('have.length', 2) + + cy.contains('Build and test the entire experience of your application').should('be.visible') + cy.percySnapshot() + }) + }) + + it('renders correct label when projects have been configured', () => { + cy.mountFragment(TestingTypeCardsFragmentDoc, { + onResult: (result, ctx) => { + if (result.currentProject) { + result.currentProject.isCTConfigured = true + result.currentProject.isE2EConfigured = true + result.currentProject.currentTestingType = null + } + }, + render: (gqlVal) => { + return + }, + }).then(() => { + cy.findAllByText(defaultMessages.setupPage.testingCard.configured).should('have.length', 2) + cy.percySnapshot() + }) + }) + + it('renders correct label when one project has been configured and the other has not', () => { + cy.mountFragment(TestingTypeCardsFragmentDoc, { + onResult: (result, ctx) => { + if (result.currentProject) { + result.currentProject.isCTConfigured = true + result.currentProject.isE2EConfigured = false + result.currentProject.currentTestingType = null + } + }, + render: (gqlVal) => { + return + }, + }).then(() => { + cy.findAllByText(defaultMessages.setupPage.testingCard.configured).should('have.length', 1) + cy.findAllByText(defaultMessages.setupPage.testingCard.notConfigured).should('have.length', 1) + + cy.contains('Build and test the entire experience of your application').should('be.visible') + cy.percySnapshot() + }) + }) + + it('renders correct label if project is initialized', () => { + cy.mountFragment(TestingTypeCardsFragmentDoc, { + onResult: (result, ctx) => { + if (result.currentProject) { + result.currentProject.isCTConfigured = true + result.currentProject.isE2EConfigured = true + result.currentProject.currentTestingType = 'component' + } + }, + render: (gqlVal) => { + return + }, + }) + + cy.findAllByText(defaultMessages.setupPage.testingCard.configured).should('have.length', 1) + cy.findAllByText(defaultMessages.setupPage.testingCard.running).should('have.length', 1) + cy.percySnapshot() + }) +}) diff --git a/packages/launchpad/src/setup/TestingTypeCards.vue b/packages/launchpad/src/setup/TestingTypeCards.vue new file mode 100644 index 0000000000..670d950574 --- /dev/null +++ b/packages/launchpad/src/setup/TestingTypeCards.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/launchpad/src/setup/Wizard.cy.tsx b/packages/launchpad/src/setup/Wizard.cy.tsx new file mode 100644 index 0000000000..f036ad3d85 --- /dev/null +++ b/packages/launchpad/src/setup/Wizard.cy.tsx @@ -0,0 +1,12 @@ +import Wizard from './Wizard.vue' +import { WizardFragmentDoc } from '../generated/graphql-test' + +describe('Wizard', () => { + it('works', () => { + cy.mountFragment(WizardFragmentDoc, { + render: (gqlVal) => { + return + }, + }) + }) +}) diff --git a/packages/launchpad/src/setup/Wizard.vue b/packages/launchpad/src/setup/Wizard.vue new file mode 100644 index 0000000000..7b32125544 --- /dev/null +++ b/packages/launchpad/src/setup/Wizard.vue @@ -0,0 +1,65 @@ + + + diff --git a/packages/launchpad/src/setup/WizardLayout.cy.tsx b/packages/launchpad/src/setup/WizardLayout.cy.tsx new file mode 100644 index 0000000000..25c1472d1f --- /dev/null +++ b/packages/launchpad/src/setup/WizardLayout.cy.tsx @@ -0,0 +1,55 @@ +import WizardLayout from './WizardLayout.vue' +import { defaultMessages } from '@cy/i18n' + +describe('', () => { + it('playground', { viewportWidth: 800, viewportHeight: 600 }, () => { + cy.mount(() => ( + +
+ content +
+
+ )) + }) + + it('renders buttons with default text', () => { + const nextFn = () => {} + const backFn = () => {} + const skipFn = () => {} + + cy.mount(() => ( + +
+ content +
+
+ )) + + cy.contains('button', defaultMessages.setupPage.step.next).should('be.visible') + cy.contains('button', defaultMessages.setupPage.step.back).should('be.visible') + cy.contains('button', defaultMessages.setupPage.step.skip).should('be.visible') + }) + + it('renders buttons with custom text', () => { + const nextFn = () => {} + const next = 'Custom next' + + const backFn = () => {} + const back = 'Custom back' + + const skipFn = () => {} + const skip = 'Custom skip' + + cy.mount(() => ( + +
+ content +
+
+ )) + + cy.contains('button', next).should('be.visible') + cy.contains('button', back).should('be.visible') + cy.contains('button', skip).should('be.visible') + }) +}) diff --git a/packages/launchpad/src/setup/WizardLayout.vue b/packages/launchpad/src/setup/WizardLayout.vue new file mode 100644 index 0000000000..6296820c20 --- /dev/null +++ b/packages/launchpad/src/setup/WizardLayout.vue @@ -0,0 +1,72 @@ + + + diff --git a/packages/launchpad/src/utils/configFile.ts b/packages/launchpad/src/utils/configFile.ts new file mode 100644 index 0000000000..a5087170c2 --- /dev/null +++ b/packages/launchpad/src/utils/configFile.ts @@ -0,0 +1,67 @@ +interface GetCode { + lang: 'js' | 'ts' + framework: { + name: string + configFile: string + } + bundler: { + name: string + package: string + } +} + +export const getCode = ({ lang, framework, bundler }: GetCode) => { + const language = languages.find((lg) => lg.id === lang) + + const comments = `Component testing, ${language?.name}, ${framework.name}, ${bundler.name}` + + if (framework.configFile) { + return `// ${comments} + +${framework.configFile[lang]}` + } + + const exportStatement = + lang === 'js' ? 'module.exports = {' : 'export default {' + + const importStatements = + lang === 'js' + ? '' + : [ + `import { startdevServer } from \'${bundler.package}\'`, + `import webpackConfig from './webpack.config'`, + '', + ].join('\n') + + const requireStatements = + lang === 'ts' + ? '' + : [ + `const { startDevServer } = require('${bundler.package}')`, + `const webpackConfig = require('./webpack.config')`, + '', + ].join('\n ') + + const startServerReturn = `return startDevServer({ options, webpackConfig })` + + return `// ${comments} +${importStatements} +${exportStatement} + ${requireStatements}component(on, config) { + on('dev-server:start', (options) => { + ${startServerReturn} + }) + } +}` +} + +export const languages: Array<{ id: 'js' | 'ts', name: string }> = [ + { + id: 'ts', + name: 'TypeScript', + }, + { + id: 'js', + name: 'JavaScript', + }, +] diff --git a/packages/launchpad/src/utils/icons.ts b/packages/launchpad/src/utils/icons.ts new file mode 100644 index 0000000000..9f56d4c388 --- /dev/null +++ b/packages/launchpad/src/utils/icons.ts @@ -0,0 +1,25 @@ +import LogoWebpack from '../images/logos/webpack.svg' +import LogoVite from '../images/logos/vite.svg' +import LogoNext from '../images/logos/nextjs.svg' +import LogoNuxt from '../images/logos/nuxt.svg' +import LogoVue from '../images/logos/vue.svg' +import LogoReact from '../images/logos/react.svg' + +import type { FrontendFrameworkEnum, SupportedBundlers } from '../generated/graphql' + +export const FrameworkBundlerLogos: Record = { + webpack4: LogoWebpack, + webpack5: LogoWebpack, + vite: LogoVite, + vue2: LogoVue, + vue3: LogoVue, + vuecli4vue2: LogoVue, + vuecli4vue3: LogoVue, + vuecli5vue2: LogoVue, + vuecli5vue3: LogoVue, + nextjs: LogoNext, + nuxtjs: LogoNuxt, + react: LogoReact, + crav4: LogoReact, + crav5: LogoReact, +} diff --git a/packages/launchpad/src/utils/logos.ts b/packages/launchpad/src/utils/logos.ts new file mode 100644 index 0000000000..24e4c148e6 --- /dev/null +++ b/packages/launchpad/src/utils/logos.ts @@ -0,0 +1,19 @@ +import LogoWebpack from '../images/logos/webpack.svg' +import LogoVite from '../images/logos/vite.svg' +import LogoNext from '../images/logos/nextjs.svg' +import LogoNuxt from '../images/logos/nuxt.svg' +import LogoVue from '../images/logos/vue.svg' +import LogoReact from '../images/logos/react.svg' + +import type { FrontendFramework, SupportedBundlers } from '../generated/graphql' + +export const FrameworkBundlerLogos: Record = { + webpack: LogoWebpack, + vite: LogoVite, + vue: LogoVue, + vuecli: LogoVue, + nextjs: LogoNext, + nuxtjs: LogoNuxt, + react: LogoReact, + cra: LogoReact, +} diff --git a/packages/launchpad/src/utils/stringToRegexp.ts b/packages/launchpad/src/utils/stringToRegexp.ts new file mode 100644 index 0000000000..ae9da249c2 --- /dev/null +++ b/packages/launchpad/src/utils/stringToRegexp.ts @@ -0,0 +1,28 @@ +export function stringToRegexp (s: string): RegExp { + return new RegExp(s) +} + +export interface FilePart { + text: string + highlight: boolean +} + +export function formatMigrationFile (file: string, regexp: RegExp): FilePart[] { + const match = regexp.exec(file) + + if (!match?.groups) { + throw Error(`Expected groups in ${file} using ${regexp}`) + } + + const higlights = Object.values(match.groups) + const delimiters = higlights.join('|') + const re = new RegExp(`(${delimiters})`) + const split = file.split(re) + + return split.map((text) => { + return { + text, + highlight: higlights.includes(text), + } + }) +} diff --git a/packages/launchpad/src/warning/WarningList.cy.tsx b/packages/launchpad/src/warning/WarningList.cy.tsx new file mode 100644 index 0000000000..7927c84888 --- /dev/null +++ b/packages/launchpad/src/warning/WarningList.cy.tsx @@ -0,0 +1,57 @@ +import { WarningListFragmentDoc } from '../generated/graphql-test' +import WarningList from './WarningList.vue' +import faker from 'faker' +import { defaultMessages } from '@cy/i18n' + +const warningSelector = '[data-cy=warning-alert]' + +const createWarning = (props = {}) => ({ + ...cy.gqlStub.ErrorWrapper, + ...props, +}) + +const firstWarning = createWarning({ title: faker.hacker.ingverb(), errorMessage: faker.hacker.phrase() }) +const secondWarning = createWarning({ title: faker.hacker.ingverb(), errorMessage: faker.hacker.phrase() }) + +describe('', () => { + it('does not render warning if there are none', () => { + cy.mountFragment(WarningListFragmentDoc, { + onResult (result) { + result.warnings = [] + }, + render: (gqlVal) =>
, + }) + + cy.get(warningSelector).should('not.exist') + }) + + it('renders multiple warnings', () => { + cy.mountFragment(WarningListFragmentDoc, { + onResult (result) { + result.warnings = [ + firstWarning, + secondWarning, + ] + }, + render: (gqlVal) =>
, + }) + + cy.get(warningSelector).should('have.length', 2) + }) + + it('removes warning when dismissed', () => { + cy.mountFragment(WarningListFragmentDoc, { + onResult (result) { + result.warnings = [firstWarning, secondWarning] + }, + render: (gqlVal) =>
, + }) + + cy.get(warningSelector).should('have.length', 2) + cy.contains(firstWarning.errorMessage) + + cy.findAllByLabelText(defaultMessages.components.modal.dismiss).first().click() + cy.get(warningSelector).should('have.length', 1) + cy.contains(firstWarning.errorMessage).should('not.exist') + }) +}) diff --git a/packages/launchpad/src/warning/WarningList.vue b/packages/launchpad/src/warning/WarningList.vue new file mode 100644 index 0000000000..e1a018d2bd --- /dev/null +++ b/packages/launchpad/src/warning/WarningList.vue @@ -0,0 +1,91 @@ + + + diff --git a/packages/launchpad/tsconfig.json b/packages/launchpad/tsconfig.json new file mode 100644 index 0000000000..2e4390dc7a --- /dev/null +++ b/packages/launchpad/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../frontend-shared/tsconfig.json", + "include": [ + "src/**/*.vue", + "src/**/*.tsx", + "*.d.ts", + "cypress/**/*.ts", + "cypress/**/*.tsx", + "../frontend-shared/src/**/*.vue", + "../frontend-shared/src/**/*.tsx", + "../frontend-shared/cypress/**/*.ts" + ], + "compilerOptions": { + "types": ["cypress", "cypress-real-events", "@intlify/vite-plugin-vue-i18n/client"], + "paths": { + "@cy/i18n": ["../frontend-shared/src/locales/i18n"], + "@cy/components/*": ["../frontend-shared/src/components/*"], + "@cy/gql-components/*": ["../frontend-shared/src/gql-components/*"], + "@packages/*": ["../*"] + } + } +} \ No newline at end of file diff --git a/packages/launchpad/vite-env.d.ts b/packages/launchpad/vite-env.d.ts new file mode 100644 index 0000000000..8cee151713 --- /dev/null +++ b/packages/launchpad/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/packages/launchpad/vite.config.ts b/packages/launchpad/vite.config.ts new file mode 100644 index 0000000000..535ebeafdd --- /dev/null +++ b/packages/launchpad/vite.config.ts @@ -0,0 +1,3 @@ +import ViteConfig from '../frontend-shared/vite.config' + +export default ViteConfig diff --git a/packages/launchpad/vue-shims.d.ts b/packages/launchpad/vue-shims.d.ts new file mode 100644 index 0000000000..6dbd5d0a2a --- /dev/null +++ b/packages/launchpad/vue-shims.d.ts @@ -0,0 +1,18 @@ +declare module 'virtual:*' { + import type { Component } from 'vue' + const src: Component + export default src +} + +declare module 'virtual:icons/*' { + // eslint-disable-next-line no-duplicate-imports + import type { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} +declare module '~icons/*' { + // eslint-disable-next-line no-duplicate-imports + import type { FunctionalComponent, SVGAttributes } from 'vue' + const component: FunctionalComponent + export default component +} diff --git a/packages/launchpad/windi.config.ts b/packages/launchpad/windi.config.ts new file mode 100644 index 0000000000..e68499f935 --- /dev/null +++ b/packages/launchpad/windi.config.ts @@ -0,0 +1,4 @@ +import { defaultConfig } from '@packages/frontend-shared/windi.config' +import { defineConfig } from 'windicss/helpers' + +export default defineConfig(defaultConfig) diff --git a/packages/net-stubbing/lib/server/middleware/error.ts b/packages/net-stubbing/lib/server/middleware/error.ts index 40c6394484..a46bda5fdf 100644 --- a/packages/net-stubbing/lib/server/middleware/error.ts +++ b/packages/net-stubbing/lib/server/middleware/error.ts @@ -3,7 +3,7 @@ import Debug from 'debug' import type { ErrorMiddleware } from '@packages/proxy' import type { CyHttpMessages } from '../../types' import _ from 'lodash' -import errors from '@packages/server/lib/errors' +import * as errors from '@packages/server/lib/errors' const debug = Debug('cypress:net-stubbing:server:intercept-error') @@ -22,7 +22,7 @@ export const InterceptError: ErrorMiddleware = async function () { await request.handleSubscriptions({ eventName: 'network:error', data: { - error: errors.clone(this.error), + error: errors.cloneErr(this.error), }, mergeChanges: _.noop, }) diff --git a/packages/net-stubbing/package.json b/packages/net-stubbing/package.json index e5e44eaf5a..f3e3782fb8 100644 --- a/packages/net-stubbing/package.json +++ b/packages/net-stubbing/package.json @@ -5,7 +5,7 @@ "main": "./lib/server", "scripts": { "build-prod": "tsc --project .", - "clean-deps": "rm -rf node_modules", + "clean-deps": "rimraf node_modules", "test": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json --exit test/unit/*" }, "dependencies": { @@ -20,7 +20,8 @@ "devDependencies": { "bin-up": "1.2.0", "chai": "4.2.0", - "mocha": "7.1.2" + "mocha": "7.1.2", + "rimraf": "3.0.2" }, "files": [ "lib" diff --git a/packages/net-stubbing/test/unit/route-matching-spec.ts b/packages/net-stubbing/test/unit/route-matching-spec.ts index 77cc7ecdd7..3c78e3934f 100644 --- a/packages/net-stubbing/test/unit/route-matching-spec.ts +++ b/packages/net-stubbing/test/unit/route-matching-spec.ts @@ -90,7 +90,7 @@ describe('intercept-request', function () { }) }) - it('doesn\'t match on a partial match', function () { + it(`doesn't match on a partial match`, function () { tryMatch({ headers: { authorization: 'basic Zm9vOmJhcg==', diff --git a/packages/network/lib/agent.ts b/packages/network/lib/agent.ts index 5f3e313af1..fb65a1b57e 100644 --- a/packages/network/lib/agent.ts +++ b/packages/network/lib/agent.ts @@ -179,10 +179,6 @@ export class CombinedAgent { hostname: options.host, port: options.port, }) + options.path - - if (!options.uri) { - options.uri = url.parse(options.href) - } } debug('addRequest called %o', { isHttps, ..._.pick(options, 'href') }) @@ -203,6 +199,20 @@ export class CombinedAgent { } } +const getProxyOrTargetOverrideForUrl = (href) => { + // HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS is used for Cypress in Cypress E2E testing and will + // force the parent Cypress server to treat the child Cypress server like a proxy without + // having HTTP_PROXY set and will force traffic ONLY bound to that origin to behave + // like a proxy + const targetHost = process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS + + if (targetHost && href.includes(targetHost)) { + return targetHost + } + + return getProxyForUrl(href) +} + class HttpAgent extends http.Agent { httpsAgent: https.Agent @@ -214,8 +224,8 @@ class HttpAgent extends http.Agent { } addRequest (req: http.ClientRequest, options: http.RequestOptions) { - if (process.env.HTTP_PROXY) { - const proxy = getProxyForUrl(options.href) + if (process.env.HTTP_PROXY || process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS) { + const proxy = getProxyOrTargetOverrideForUrl(options.href) if (proxy) { options.proxy = proxy @@ -269,6 +279,23 @@ class HttpsAgent extends https.Agent { super(opts) } + addRequest (req: http.ClientRequest, options: http.RequestOptions) { + if (!options.uri) { + options.uri = url.parse(options.href) + } + + // Ensure we have a proper port defined otherwise node has assumed we are port 80 + // (https://github.com/nodejs/node/blob/master/lib/_http_client.js#L164) since we are a combined agent + // rather than an http or https agent. This will cause issues with fetch requests (@cypress/request already handles it: + // https://github.com/cypress-io/request/blob/master/request.js#L301-L303) + if (!options.uri.port && options.uri.protocol === 'https:') { + options.uri.port = String(443) + options.port = 443 + } + + super.addRequest(req, options) + } + createConnection (options: HttpsRequestOptions, cb: http.SocketCallback) { if (process.env.HTTPS_PROXY) { const proxy = getProxyForUrl(options.href) diff --git a/packages/network/lib/client-certificates.ts b/packages/network/lib/client-certificates.ts index 789c8236fd..ec6fcfac09 100644 --- a/packages/network/lib/client-certificates.ts +++ b/packages/network/lib/client-certificates.ts @@ -1,9 +1,10 @@ -import type { Url } from 'url' +import { URL, Url } from 'url' import debugModule from 'debug' import minimatch from 'minimatch' import Forge from 'node-forge' import fs from 'fs-extra' import { clientCertificateStore } from './agent' + const { pki, asn1, pkcs12, util } = Forge const debug = debugModule('cypress:network:client-certificates') @@ -271,7 +272,7 @@ export function loadClientCertificateConfig (config) { if (passphrase) { if (!pki.decryptRsaPrivateKey(pemKeyRaw, passphrase)) { throw new Error( - 'Cannot decrypt PEM key with supplied passphrase (check the passphrase file content and that it doesn\'t have unexpected whitespace at the end)', + `Cannot decrypt PEM key with supplied passphrase (check the passphrase file content and that it doesn't have unexpected whitespace at the end)`, ) } } else { diff --git a/packages/network/package.json b/packages/network/package.json index 0132151b53..349a35f841 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -5,8 +5,8 @@ "main": "index.js", "scripts": { "build-prod": "tsc --project .", - "clean": "rm lib/*.js", - "clean-deps": "rm -rf node_modules", + "clean": "rimraf 'lib/**/*.js'", + "clean-deps": "rimraf node_modules", "test": "yarn test-unit", "test-debug": "yarn test-unit --inspect-brk=5566", "test-unit": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json", @@ -32,6 +32,7 @@ "@types/concat-stream": "1.6.0", "express": "4.17.1", "mocha": "6.2.2", + "rimraf": "3.0.2", "sinon": "7.3.1", "sinon-chai": "3.3.0", "typescript": "^4.2.3" diff --git a/packages/network/test/unit/agent_spec.ts b/packages/network/test/unit/agent_spec.ts index eb3264434f..dbb07fe7aa 100644 --- a/packages/network/test/unit/agent_spec.ts +++ b/packages/network/test/unit/agent_spec.ts @@ -9,7 +9,7 @@ import tls from 'tls' import url from 'url' import DebuggingProxy from '@cypress/debugging-proxy' import request from '@cypress/request-promise' -import * as socketIo from '@packages/socket' +import * as socketIo from '@packages/socket/lib/browser' import { buildConnectReqHead, createProxySock, @@ -23,6 +23,8 @@ import { allowDestroy } from '../../lib/allow-destroy' import { AsyncServer, Servers } from '../support/servers' import { UrlClientCertificates, ClientCertificates, PemKey } from '../../lib/client-certificates' import Forge from 'node-forge' +import fetch from 'cross-fetch' +import os from 'os' const { pki } = Forge const expect = chai.expect @@ -31,7 +33,7 @@ chai.use(sinonChai) const PROXY_PORT = 31000 const HTTP_PORT = 31080 -const HTTPS_PORT = 31443 +const HTTPS_PORT = 443 function createCertAndKey (): [object, object] { let keys = pki.rsa.generateKeyPair(2048) @@ -80,10 +82,21 @@ function createCertAndKey (): [object, object] { describe('lib/agent', function () { beforeEach(function () { process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' + + try { + // Disabling the eslint for geteuid since we are explicitly catching if there's a problem with it + // eslint-disable-next-line + if (os.platform() === 'linux' && process.geteuid && process.geteuid() !== 0) { + // eslint-disable-next-line no-console + console.error('You must be a root user to run these tests since we specifically test hosting a server at 443 which requires root access') + } + } catch (error) { + // OK to do nothing here since geteuid is only a problem on windows + } }) afterEach(function () { - process.env.NO_PROXY = process.env.HTTP_PROXY = process.env.HTTPS_PROXY = '' + process.env.NO_PROXY = process.env.HTTP_PROXY = process.env.HTTPS_PROXY = process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS = '' sinon.restore() }) @@ -142,6 +155,13 @@ describe('lib/agent', function () { agent: this.agent, }) + this.fetch = function (this: any, input: RequestInfo, init?: RequestInit) { + return fetch.call(this, input, { + agent: this.agent, + ...init, + }) + } + if (testCase.proxyUrl) { let options: any = { keepRequests: true, @@ -185,6 +205,19 @@ describe('lib/agent', function () { }) }) + it('HTTP pages can be loaded via fetch', function () { + return this.fetch(`http://localhost:${HTTP_PORT}/get`) + .then((response) => response.text()) + .then((body) => { + expect(body).to.eq('It worked!') + if (this.debugProxy) { + expect(this.debugProxy.requests[0]).to.include({ + url: `http://localhost:${HTTP_PORT}/get`, + }) + } + }) + }) + it('HTTPS pages can be loaded', function () { return this.request({ url: `https://localhost:${HTTPS_PORT}/get`, @@ -199,6 +232,34 @@ describe('lib/agent', function () { }) }) + it('HTTPS pages can be loaded via fetch', function () { + return this.fetch(`https://localhost:${HTTPS_PORT}/get`) + .then((response) => response.text()) + .then((body) => { + expect(body).to.eq('It worked!') + if (this.debugProxy) { + expect(this.debugProxy.requests[0]).to.include({ + https: true, + url: `localhost:${HTTPS_PORT}`, + }) + } + }) + }) + + it('HTTPS pages can be loaded via fetch with no explicit port', function () { + return this.fetch(`https://localhost/get`) + .then((response) => response.text()) + .then((body) => { + expect(body).to.eq('It worked!') + if (this.debugProxy) { + expect(this.debugProxy.requests[0]).to.include({ + https: true, + url: `localhost:${HTTPS_PORT}`, + }) + } + }) + }) + it('HTTP errors are catchable', function () { return this.request({ url: `http://localhost:${HTTP_PORT}/empty-response`, @@ -266,7 +327,7 @@ describe('lib/agent', function () { expect(msg).to.eq('It worked!') if (this.debugProxy) { expect(this.debugProxy.requests[0]).to.include({ - url: 'localhost:31443', + url: `localhost:${HTTPS_PORT}`, }) } @@ -413,6 +474,20 @@ describe('lib/agent', function () { }) }) }) + + it('HTTP pages can be loaded with the Upstream target URL', function (done) { + process.env.HTTP_PROXY = process.env.HTTPS_PROXY = '' + process.env.NO_PROXY = '' + process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS = `http://localhost:${HTTP_PORT}` + + this.request({ + url: `http://localhost:${HTTP_PORT}/get`, + }).on('response', (response) => { + expect(response.req.path).to.equal('http://localhost:31080/get') + + done() + }) + }) }) }) diff --git a/packages/network/test/unit/client_certificates_spec.ts b/packages/network/test/unit/client_certificates_spec.ts index a942f0f600..2d0fd6e7a8 100644 --- a/packages/network/test/unit/client_certificates_spec.ts +++ b/packages/network/test/unit/client_certificates_spec.ts @@ -554,7 +554,7 @@ describe('lib/client-certificates', () => { } expect(act).to.throw( - 'Cannot decrypt PEM key with supplied passphrase (check the passphrase file content and that it doesn\'t have unexpected whitespace at the end)', + `Cannot decrypt PEM key with supplied passphrase (check the passphrase file content and that it doesn't have unexpected whitespace at the end)`, ) }) diff --git a/packages/proxy/lib/http/error-middleware.ts b/packages/proxy/lib/http/error-middleware.ts index 43de4c39bf..aed898b6fd 100644 --- a/packages/proxy/lib/http/error-middleware.ts +++ b/packages/proxy/lib/http/error-middleware.ts @@ -1,10 +1,10 @@ import debugModule from 'debug' +import * as errors from '@packages/server/lib/errors' + import type { HttpMiddleware } from '.' import type { Readable } from 'stream' import { InterceptError } from '@packages/net-stubbing' import type { Request } from '@cypress/request' -import errors from '@packages/server/lib/errors' - const debug = debugModule('cypress:proxy:http:error-middleware') export type ErrorMiddleware = HttpMiddleware<{ @@ -27,7 +27,7 @@ const SendToDriver: ErrorMiddleware = function () { if (this.req.browserPreRequest) { this.socket.toDriver('request:event', 'request:error', { requestId: this.req.browserPreRequest.requestId, - error: errors.clone(this.error), + error: errors.cloneErr(this.error), }) } diff --git a/packages/proxy/lib/http/request-middleware.ts b/packages/proxy/lib/http/request-middleware.ts index e697fff4b8..61756212c6 100644 --- a/packages/proxy/lib/http/request-middleware.ts +++ b/packages/proxy/lib/http/request-middleware.ts @@ -167,14 +167,22 @@ const SendRequestOutgoing: RequestMiddleware = function () { } const req = this.request.create(requestOptions) + const socket = this.req.socket + + const onSocketClose = () => { + this.debug('request aborted') + req.abort() + } req.on('error', this.onError) req.on('response', (incomingRes) => this.onResponse(incomingRes, req)) - this.req.socket.on('close', () => { - this.debug('request aborted') - req.abort() + + this.req.res?.on('finish', () => { + socket.removeListener('close', onSocketClose) }) + this.req.socket.on('close', onSocketClose) + if (!requestBodyBuffered) { // pipe incoming request body, headers to new request this.req.pipe(req) diff --git a/packages/proxy/lib/http/response-middleware.ts b/packages/proxy/lib/http/response-middleware.ts index 52d64534bc..b936dcb078 100644 --- a/packages/proxy/lib/http/response-middleware.ts +++ b/packages/proxy/lib/http/response-middleware.ts @@ -11,6 +11,7 @@ import { InterceptResponse } from '@packages/net-stubbing' import { PassThrough, Readable } from 'stream' import * as rewriter from './util/rewriter' import zlib from 'zlib' +import { URL } from 'url' export type ResponseMiddleware = HttpMiddleware<{ /** diff --git a/packages/proxy/package.json b/packages/proxy/package.json index 2d2fb5dc9b..4a17cee443 100644 --- a/packages/proxy/package.json +++ b/packages/proxy/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "build-prod": "tsc --project .", - "clean-deps": "rm -rf node_modules", + "clean": "rimraf 'lib/**/*.js'", + "clean-deps": "rimraf node_modules", "run-mocha": "mocha -r @packages/ts/register -r test/pretest.ts --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json", "test": "yarn run-mocha \"test/integration/*.spec.ts\" \"test/unit/**/*.spec.ts\"", "test-integration": "yarn run-mocha \"test/integration/*.spec.ts\"", @@ -31,6 +32,7 @@ "@types/express": "4.17.2", "@types/supertest": "2.0.10", "express": "4.17.1", + "rimraf": "3.0.2", "supertest": "6.0.1", "typescript": "^4.2.3" }, diff --git a/packages/proxy/test/unit/http/response-middleware.spec.ts b/packages/proxy/test/unit/http/response-middleware.spec.ts index 0ba4b6c523..b168d7db63 100644 --- a/packages/proxy/test/unit/http/response-middleware.spec.ts +++ b/packages/proxy/test/unit/http/response-middleware.spec.ts @@ -48,7 +48,7 @@ describe('http/response-middleware', function () { prepareContext() }) - it('doesn\'t do anything', function () { + it(`doesn't do anything`, function () { return testMiddleware([MaybeStripDocumentDomainFeaturePolicy], ctx) .then(() => { expect(ctx.res.set).not.to.be.called @@ -62,7 +62,7 @@ describe('http/response-middleware', function () { prepareContext() }) - it('doesn\'t do anything', function () { + it(`doesn't do anything`, function () { return testMiddleware([MaybeStripDocumentDomainFeaturePolicy], ctx) .then(() => { expect(ctx.res.set).not.to.be.called diff --git a/packages/reporter/cypress.config.ts b/packages/reporter/cypress.config.ts new file mode 100644 index 0000000000..c767e3848d --- /dev/null +++ b/packages/reporter/cypress.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + projectId: 'ypt4pf', + reporter: '../../node_modules/cypress-multi-reporters/index.js', + reporterOptions: { + configFile: '../../mocha-reporter-config.json', + }, + retries: { + runMode: 2, + openMode: 0, + }, + e2e: { + baseUrl: 'http://localhost:5006', + setupNodeEvents (_on, config) { + const express = require('express') + + express().use(express.static('dist')).listen(5006) + + return config + }, + viewportHeight: 660, + viewportWidth: 400, + }, +}) diff --git a/packages/reporter/cypress.json b/packages/reporter/cypress.json deleted file mode 100644 index 8110d4801e..0000000000 --- a/packages/reporter/cypress.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "projectId": "ypt4pf", - "baseUrl": "http://localhost:5006", - "viewportWidth": 400, - "viewportHeight": 1000, - "reporter": "../../node_modules/cypress-multi-reporters/index.js", - "reporterOptions": { - "configFile": "../../mocha-reporter-config.json" - }, - "retries": { - "runMode": 2, - "openMode": 0 - } -} diff --git a/packages/reporter/cypress/e2e/agents.cy.ts b/packages/reporter/cypress/e2e/agents.cy.ts new file mode 100644 index 0000000000..163beeaf48 --- /dev/null +++ b/packages/reporter/cypress/e2e/agents.cy.ts @@ -0,0 +1,123 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from './../../src/runnables/runnables-store' + +describe('agents', () => { + let runner: EventEmitter + let runnables: RootRunnable + let start: Function + + beforeEach(() => { + cy.fixture('runnables_agents').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + }) + }) + + start = () => { + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + + cy.contains('http://localhost:3000') // ensure test content has loaded + } + }) + + it('does not display agents if there are no agents', () => { + // @ts-ignore + runnables.tests[0].agents = [] + start() + + cy.contains('Spies / Stubs').should('not.be.visible') + }) + + describe('when there are agents', () => { + it('displays collapsible header with number of agents', () => { + start() + cy.contains('Spies / Stubs (3)').should('be.visible') + }) + + it('collapses agents by default', () => { + start() + cy.get('.runnable-agents-region .instrument-content').should('not.be.visible') + }) + + it('shows agents after expanding', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.runnable-agents-region .instrument-content').should('be.visible') + cy.percySnapshot() + }) + + it('displays each of the agents', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').should('have.length', 3) + }) + + it('does not include no-calls class if there is a non-zero callCount', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').first().should('not.have.class', 'no-calls') + }) + + it('includes no-calls class if zero callCount', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').eq(2).should('have.class', 'no-calls') + }) + + it('displays the type', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').eq(0).find('td').first().should('have.text', 'spy') + cy.get('.agent-item').eq(1).find('td').first().should('have.text', 'stub-1') + cy.get('.agent-item').eq(2).find('td').first().should('have.text', 'stub-2') + }) + + it('displays the function name', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').eq(0).find('td').eq(1).should('have.text', 'get') + cy.get('.agent-item').eq(1).find('td').eq(1).should('have.text', 'fetch') + cy.get('.agent-item').eq(2).find('td').eq(1).should('have.text', 'go') + }) + + it('displays alias when singular or multiple, but not when absent', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').eq(0).find('td').eq(2).should('have.text', 'getAlias') + cy.get('.agent-item').eq(1).find('td').eq(2).should('have.text', 'fetchAlias, gonnaHappenAlias') + cy.get('.agent-item').eq(2).find('td').eq(2).should('have.text', '') + }) + + it('displays the callCount if non-zero or "-" if zero', () => { + start() + cy.contains('Spies / Stubs (3)').click() + + cy.get('.agent-item').eq(0).find('td').eq(3).should('have.text', '1') + cy.get('.agent-item').eq(1).find('td').eq(3).should('have.text', '3') + cy.get('.agent-item').eq(2).find('td').eq(3).should('have.text', '-') + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/aliases.cy.ts b/packages/reporter/cypress/e2e/aliases.cy.ts new file mode 100644 index 0000000000..b044662fa0 --- /dev/null +++ b/packages/reporter/cypress/e2e/aliases.cy.ts @@ -0,0 +1,656 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from './../../src/runnables/runnables-store' +import { addCommand } from '../support/utils' + +describe('aliases', () => { + let runner: EventEmitter + let runnables: RootRunnable + + beforeEach(() => { + cy.fixture('runnables_aliases').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + }) + + context('interceptions + status', () => { + it('shows only status if no alias or dupe', () => { + addCommand(runner, { + aliasType: 'route', + renderProps: { + wentToOrigin: true, + status: 'some status', + interceptions: [{ + type: 'spy', + command: 'intercept', + }], + }, + }) + + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-interceptions') + .should('have.text', 'some status no alias') + .trigger('mouseover') + .get('.cy-tooltip') + .should('have.text', 'This request matched:cy.intercept() spy with no alias') + .percySnapshot() + }) + + it('shows status and count if dupe', () => { + addCommand(runner, { + aliasType: 'route', + renderProps: { + wentToOrigin: true, + status: 'some status', + interceptions: [{ + type: 'spy', + command: 'intercept', + }, { + type: 'spy', + command: 'route', + }], + }, + }) + + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-interceptions') + .should('have.text', 'some status no alias') + .parent().find('.command-interceptions-count') + .should('have.text', '2') + .trigger('mouseover') + .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with no aliascy.route() spy with no alias') + .percySnapshot() + }) + + it('shows status and alias and count if dupe', () => { + addCommand(runner, { + aliasType: 'route', + alias: 'myAlias', + renderProps: { + wentToOrigin: true, + status: 'some status', + interceptions: [{ + type: 'spy', + command: 'intercept', + alias: 'firstAlias', + }, { + type: 'spy', + command: 'intercept', + alias: 'myAlias', + }], + }, + }) + + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-interceptions') + .should('have.text', 'some status myAlias') + .parent().find('.command-interceptions-count') + .should('have.text', '2') + .trigger('mouseover') + .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with alias @firstAliascy.intercept() spy with alias @myAlias') + .percySnapshot() + }) + + it('shows status and alias', () => { + addCommand(runner, { + aliasType: 'route', + alias: 'myAlias', + renderProps: { + wentToOrigin: true, + status: 'some status', + interceptions: [{ + type: 'spy', + command: 'intercept', + alias: 'myAlias', + }], + }, + }) + + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-interceptions') + .should('have.text', 'some status myAlias') + .trigger('mouseover') + .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with alias @myAlias') + .percySnapshot() + }) + }) + + context('route aliases', () => { + describe('without duplicates', () => { + beforeEach(() => { + addCommand(runner, { + alias: 'getUsers', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + renderProps: { + message: 'GET --- /users', + indicator: 'successful', + wentToOrigin: false, + interceptions: [{ + type: 'stub', + command: 'route', + alias: 'getUsers', + }], + }, + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getUsers, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 1, + name: 'getUsers', + ordinal: '1st', + }], + }) + }) + + it('has correct alias class', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-alias') + .should('have.class', 'route') + }) + + it('render without a count', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@getUsers') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'getUsers\'') + }) + + cy.percySnapshot() + }) + }) + + describe('with consecutive duplicates', () => { + beforeEach(() => { + addCommand(runner, { + alias: 'getPosts', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + // @ts-ignore + renderProps: { message: 'GET --- /posts', indicator: 'successful', interceptions: [{ alias: 'getPosts' }] }, + }) + + addCommand(runner, { + alias: 'getPosts', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + // @ts-ignore + renderProps: { message: 'GET --- /posts', indicator: 'successful', interceptions: [{ alias: 'getPosts' }] }, + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getPosts, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 1, + name: 'getPosts', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getPosts, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 2, + name: 'getPosts', + ordinal: '2nd', + }], + }) + }) + + it('renders all aliases ', () => { + cy.get('.command-alias').should('have.length', 2) + cy.percySnapshot() + }) + + it('render with counts in non-event commands', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.contains('.command-alias-count', '1') + + cy.contains('.command-alias', '@getPosts') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found 1st alias for: \'getPosts\'') + }) + + cy.contains('.command-number', '2') + .should('be.visible') + .closest('.command-wrapper') + .within(() => { + cy.contains('.command-alias-count', '2') + + cy.contains('.command-alias', '@getPosts') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found 2nd alias for: \'getPosts\'') + }) + }) + + it('render with counts in event commands when collapsed', () => { + cy.get('.command-wrapper') + .first() + .within(() => { + cy.contains('.num-children', '2').should('be.visible') + + cy.contains('.command-interceptions', 'getPosts') + }) + }) + + it('render without counts in event commands when expanded', () => { + cy.get('.command-expander') + .first() + .click() + + cy.get('.command-wrapper') + .first() + .within(() => { + cy.get('.num-children').should('not.exist') + + cy.contains('.command-interceptions', 'getPosts') + }) + }) + }) + + describe('with non-consecutive duplicates', () => { + beforeEach(() => { + addCommand(runner, { + alias: 'getPosts', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + renderProps: { + message: 'GET --- /users', + indicator: 'successful', + wentToOrigin: false, + interceptions: [{ + type: 'stub', + command: 'route', + alias: 'getUsers', + }], + }, + }) + + addCommand(runner, { + alias: 'getUsers', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + renderProps: { + message: 'GET --- /users', + indicator: 'successful', + wentToOrigin: false, + interceptions: [{ + type: 'stub', + command: 'route', + alias: 'getUsers', + }], + }, + }) + + addCommand(runner, { + alias: 'getPosts', + aliasType: 'route', + displayName: 'xhr', + event: true, + name: 'xhr', + renderProps: { + message: 'GET --- /posts', + indicator: 'successful', + wentToOrigin: false, + interceptions: [{ + type: 'stub', + command: 'route', + alias: 'getPosts', + }], + }, + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getPosts, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 1, + name: 'getPosts', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getUsers, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 1, + name: 'getUsers', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'route', + message: '@getPosts, function(){}', + name: 'wait', + referencesAlias: [{ + cardinal: 2, + name: 'getPosts', + ordinal: '2nd', + }], + }) + }) + + it('render with counts', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.contains('.command-alias-count', '1') + + cy.contains('.command-alias', '@getPosts') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found 1st alias for: \'getPosts\'') + }) + + cy.contains('.command-number', '3') + .closest('.command-wrapper') + .within(() => { + cy.contains('.command-alias-count', '2') + + cy.contains('.command-alias', '@getPosts') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found 2nd alias for: \'getPosts\'') + }) + + cy.percySnapshot() + }) + }) + }) + + context('element aliases', () => { + describe('without duplicates', () => { + beforeEach(() => { + addCommand(runner, { + state: 'passed', + name: 'get', + message: 'body', + alias: 'barAlias', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 1, + name: 'barAlias', + ordinal: '1st', + }], + }) + }) + + it('has correct alias class', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .find('.command-alias') + .should('have.class', 'dom') + }) + + it('render without a count', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@barAlias') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'barAlias\'') + }) + }) + }) + + describe('with consecutive duplicates', () => { + beforeEach(() => { + addCommand(runner, { + state: 'passed', + name: 'get', + message: '[attr=\'dropdown\']', + alias: 'dropdown', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + state: 'passed', + name: 'get', + message: 'select', + alias: 'dropdown', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 1, + name: 'dropdown', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 2, + name: 'dropdown', + ordinal: '2nd', + }], + }) + }) + + it('render without a count in non-event commands', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@dropdown') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'dropdown\'') + }) + + cy.contains('.command-number', '2') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@dropdown') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'dropdown\'') + }) + }) + + it('render without counts in event commands when collapsed', () => { + cy.get('.command-wrapper') + .first() + .within(() => { + cy.get('.num-children').should('not.exist') + + cy.contains('.command-alias', 'dropdown') + }) + }) + }) + + describe('with non-consecutive duplicates', () => { + beforeEach(() => { + addCommand(runner, { + state: 'passed', + name: 'get', + message: '[attr=\'dropdown\']', + alias: 'dropdown', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + state: 'passed', + name: 'get', + message: '[attr=\'modal\']', + alias: 'modal', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + state: 'passed', + name: 'get', + message: '[attr=\'dropdown\']', + alias: 'dropdown', + aliasType: 'dom', + event: true, + renderProps: { message: '', indicator: 'successful' }, + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 1, + name: 'dropdown', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 1, + name: 'modal', + ordinal: '1st', + }], + }) + + addCommand(runner, { + aliasType: 'dom', + message: '', + name: 'get', + referencesAlias: [{ + cardinal: 2, + name: 'dropdown', + ordinal: '2nd', + }], + }) + }) + + it('renders all aliases ', () => { + cy.get('.command-alias').should('have.length', 6) + }) + + it('render without counts', () => { + cy.contains('.command-number', '1') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@dropdown') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'dropdown\'') + }) + + cy.contains('.command-number', '3') + .closest('.command-wrapper') + .within(() => { + cy.get('.command-alias-count').should('not.exist') + + cy.contains('.command-alias', '@dropdown') + .trigger('mouseover') + }) + + cy.get('.cy-tooltip span').should(($tooltip) => { + expect($tooltip).to.contain('Found an alias for: \'dropdown\'') + }) + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/commands.cy.ts b/packages/reporter/cypress/e2e/commands.cy.ts new file mode 100644 index 0000000000..0c308a42c4 --- /dev/null +++ b/packages/reporter/cypress/e2e/commands.cy.ts @@ -0,0 +1,545 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from '../../src/runnables/runnables-store' +import { addCommand } from '../support/utils' + +describe('commands', () => { + let runner: EventEmitter + let runnables: RootRunnable + const inProgressStartedAt = (new Date(2000, 0, 1)).toISOString() + + beforeEach(() => { + cy.fixture('runnables_commands').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + addCommand(runner, { + id: 9, + name: 'get', + message: '#in-progress', + state: 'pending', + timeout: 4000, + wallClockStartedAt: inProgressStartedAt, + }) + }) + + cy.contains('http://localhost:3000') // ensure test content has loaded + }) + + it('displays all the commands', () => { + cy.get('.command').should('have.length', 10) + + cy.percySnapshot() + }) + + it('includes the type class', () => { + cy.contains('#exists').closest('.command-wrapper') + .should('have.class', 'command-type-parent') + + cy.contains('#doesnt-exist').closest('.command-wrapper') + .should('have.class', 'command-type-child') + }) + + it('includes the name class', () => { + cy.contains('#exists').closest('.command') + .should('have.class', 'command-name-get') + }) + + it('includes the state class', () => { + cy.contains('#exists').closest('.command-wrapper') + .should('have.class', 'command-state-passed') + + cy.contains('#doesnt-exist').closest('.command-wrapper') + .should('have.class', 'command-state-failed') + + cy.contains('#in-progress').closest('.command-wrapper') + .should('have.class', 'command-state-pending') + }) + + it('displays the number for parent and child', () => { + cy.contains('http://localhost:3000') + .closest('.command-message') + .siblings('.command-number-column') + .should('have.text', '1') + + cy.contains('#exists').closest('.command-message').siblings('.command-number-column') + .should('have.text', '2') + + cy.contains('#doesnt-exist').closest('.command-message').siblings('.command-number-column') + .should('have.text', '3') + + cy.contains('.some-els').closest('.command-message').siblings('.command-number-column') + .should('have.text', '4') + }) + + it('events have is-event class, no number, and type in parentheses', () => { + cy.contains('GET ---').closest('.command-wrapper') + .should('have.class', 'command-is-event') + + cy.contains('GET ---').closest('.command-message').siblings('.command-number-column') + .should('have.text', '') + + cy.contains('GET ---').closest('.command-message').siblings('.command-method') + .should('have.text', '(xhr stub)') + }) + + it('includes the scaled class when the message is over 100 chars', () => { + cy.contains('Lorem ipsum').closest('.command') + .should('have.class', 'command-scaled') + }) + + it('does not render with the scaled class when the message is less than 100 chars', () => { + cy.contains('#exists').closest('.command') + .should('not.have.class', 'command-scaled') + }) + + it('renders markdown in message', () => { + cy.contains('Lorem ipsum').closest('.command').find('.command-message').within(() => { + cy.get('strong').should('have.text', 'dolor') + cy.get('em').should('have.text', 'sit') + }) + }) + + it('shows message indicator when specified', () => { + const indicators = ['successful', 'pending', 'aborted', 'bad'] + + indicators.forEach((indicator) => { + addCommand(runner, { + name: 'xhr', + event: true, + renderProps: { + indicator, + message: `${indicator} indicator`, + }, + }) + }) + + indicators.forEach((indicator) => { + cy.contains(`${indicator} indicator`).closest('.command').find('.command-message .fa-circle') + .should('have.class', `command-message-indicator-${indicator}`) + }) + + cy.percySnapshot() + }) + + it('assert commands for each state', () => { + const assertStates = ['passed', 'pending', 'failed'] + + assertStates.forEach((state) => { + addCommand(runner, { + name: 'assert', + type: 'child', + message: `expected **element** to have **state of ${state}**`, + state, + }) + }) + + cy.get('.command').should('have.length', 13) + + cy.percySnapshot() + }) + + describe('progress bar', () => { + const getProgress = () => { + return cy.contains('#in-progress') + .closest('.command') + .find('.command-progress span') + } + + it('calculates correct scale factor', () => { + // take the wallClockStartedAt of this command and add 2500 milliseconds to it + // in order to simulate the command having run for 2.5 seconds of the total 4000 timeout + const date = new Date(inProgressStartedAt).setMilliseconds(2500) + + cy.clock(date, ['Date']) + // close and open tests so it freshly mounts + cy.contains('test 1').click().click() + getProgress().should(($span) => { + expect($span.attr('style')).to.contain('animation-duration: 1500ms') + expect($span.attr('style')).to.contain('transform: scaleX(0.375)') + + // ensures that actual scale factor hits 0 within default timeout + // this matrix is equivalent to scaleX(0) + expect($span).to.have.css('transform', 'matrix(0, 0, 0, 1, 0, 0)') + }) + }) + + it('recalculates correct scale factor after being closed', () => { + // take the wallClockStartedAt of this command and add 1000 milliseconds to it + // in order to simulate the command having run for 1 second of the total 4000 timeout + const date = new Date(inProgressStartedAt).setMilliseconds(1000) + + cy.clock(date, ['Date']) + // close and open tests so it freshly mounts + cy.contains('test').click().click() + getProgress().should(($span) => { + expect($span.attr('style')).to.contain('animation-duration: 3000ms') + expect($span.attr('style')).to.contain('transform: scaleX(0.75)') + }) + + // set the clock ahead as if time has passed + cy.tick(2000) + + cy.contains('test 1').click().click() + getProgress().should(($span) => { + expect($span.attr('style')).to.contain('animation-duration: 1000ms') + expect($span.attr('style')).to.contain('transform: scaleX(0.25)') + }) + }) + }) + + context('invisible indicator', () => { + it('does not render invisible icon when visible', () => { + cy.contains('#exists').closest('.command').find('.command-invisible') + .should('not.exist') + }) + + it('displays invisible icon when not visible', () => { + cy.contains('#doesnt-exist').closest('.command').find('.command-invisible') + .should('be.visible') + }) + + it('displays a tooltip when hovering', () => { + cy.contains('#doesnt-exist').closest('.command').find('.command-invisible').trigger('mouseover') + cy.get('.cy-tooltip') + .should('be.visible') + .should('have.text', 'This element is not visible.') + }) + + it('displays different text when multiple elements', () => { + cy.contains('.invisible').closest('.command').find('.command-invisible').trigger('mouseover') + cy.get('.cy-tooltip') + .should('be.visible') + .should('have.text', 'One or more matched elements are not visible.') + }) + }) + + context('elements indicator', () => { + it('shows number of elements when 0 or greater than 1', () => { + cy.contains('#doesnt-exist').closest('.command').find('.num-elements') + .should('be.visible').and('have.text', '0') + + cy.contains('.some-els').closest('.command').find('.num-elements') + .should('be.visible').and('have.text', '4') + }) + + it('does not render number of elements when 1', () => { + cy.contains('#exist').closest('.command').find('.num-elements') + .should('not.exist') + }) + + it('renders a tooltip when hovering', () => { + cy.contains('.some-els').closest('.command').find('.num-elements').trigger('mouseover') + cy.get('.cy-tooltip').should('be.visible').should('have.text', '4 matched elements') + }) + }) + + context('event duplicates', () => { + it('collapses consecutive duplicate events into group', () => { + cy.get('.command-name-xhr').should('have.length', 3) + }) + + it('displays number of duplicates', () => { + cy.contains('GET --- /dup') + .closest('.command') + .find('.num-children') + .should('be.visible') + .should('have.text', '4') + .trigger('mouseover') + .get('.cy-tooltip').should('have.text', 'This event occurred 4 times') + }) + + it('expands all events after clicking arrow', () => { + cy.contains('GET --- /dup').closest('.command').find('.command-child-container').should('not.exist') + cy.contains('GET --- /dup') + .closest('.command') + .find('.command-expander') + .click() + + cy.get('.command-name-xhr').should('have.length', 6) + cy.contains('GET --- /dup').closest('.command').find('.command-child-container') + .should('be.visible') + .find('.command').should('have.length', 3) + }) + }) + + context('clicking command', () => { + it('pins the command', () => { + cy.get('.command:nth-child(2)') + .should('contain', '#exists') + .trigger('mouseover') + .click() + .closest('.command') + .find('.command-wrapper') + .should('have.class', 'command-is-pinned') + .find('.command-pin') + }) + + it('shows a tooltip', () => { + cy.contains('#exists').click() + cy.get('.cy-tooltip').should('have.text', 'Printed output to your console') + }) + + it('tooltip disappears after 1500ms', () => { + cy.clock() + cy.contains('#exists').click() + cy.tick(1500) + cy.get('.cy-tooltip').should('not.exist') + }) + + it('prints to console', () => { + cy.spy(runner, 'emit') + cy.contains('#exists').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:console:log', 2) + }) + + it('shows the snapshot', () => { + cy.spy(runner, 'emit') + cy.contains('#exists').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:show:snapshot', 2) + }) + + it('unpins after clicking again, does not re-print to the console', () => { + cy.spy(runner, 'emit') + cy.contains('#exists').click() + cy.contains('#exists').click() + // @ts-ignore + cy.wrap(runner.emit.withArgs('runner:console:log')).should('be.calledOnce') + }) + + it('unpins after clicking another command, pins that one', () => { + cy.spy(runner, 'emit') + cy.contains('#exists').click() + cy.contains('#doesnt-exist').click() + cy.contains('#exists').closest('.command-wrapper') + .should('not.have.class', 'command-is-pinned') + + cy.contains('#doesnt-exist').closest('.command-wrapper') + .should('have.class', 'command-is-pinned') + }) + }) + + context('command group', () => { + let groupId + + beforeEach(() => { + addCommand(runner, { + name: 'get', + message: '#my_element', + }) + + groupId = addCommand(runner, { + name: 'within', + type: 'child', + }) + + addCommand(runner, { + name: 'get', + message: '#my_nested_element', + group: groupId, + }) + }) + + it('group is open by default when all nested command have passed', () => { + addCommand(runner, { + name: 'log', + message: 'chained log example', + }) + + cy.contains('chained log example') // ensure test content has loaded + + cy.get('.command-name-within') + .find('.command-expander') + .should('have.class', 'command-expander-is-open') + .click() + + cy.get('.command-name-within') + .find('.num-children') + .should('have.text', '1') + .trigger('mouseover') + .get('.cy-tooltip').should('have.text', '1 log currently hidden') + .percySnapshot() + }) + + it('group is closed by default when last nested command failed', () => { + addCommand(runner, { + name: 'log', + message: 'chained log example', + state: 'failed', + group: groupId, + }) + + cy.contains('chained log example') // ensure test content has loaded + + cy.get('.command-name-within') + .find('.command-expander') + .should('have.class', 'command-expander-is-open') + + cy.get('.command-name-within') + .find('.num-children') + .should('not.exist') + .percySnapshot() + }) + + it('clicking opens and closes the group', () => { + cy.get('.command-name-within') + .find('.command-expander') + .should('have.class', 'command-expander-is-open') + .click() + + cy.get('.command-name-within') + .find('.command-expander') + .should('not.have.class', 'command-expander-is-open') + .closest('.command') + .find('.num-children') + .should('have.text', '1') + + cy.get('.command-name-within') + .find('.command-expander') + .click() + .should('have.class', 'command-expander-is-open') + + cy.get('.command-name-within') + .find('.num-children') + .should('not.exist') + }) + + it('displays with nested logs', () => { + const nestedGroupId = addCommand(runner, { + name: 'within2', + state: 'passed', + type: 'child', + group: groupId, + }) + + addCommand(runner, { + name: 'get', + message: '#my_element_nested', + state: 'passed', + group: nestedGroupId, + }) + + addCommand(runner, { + name: 'assert', + type: 'child', + message: 'has class named .omg', + group: nestedGroupId, + }) + + addCommand(runner, { + name: 'log', + message: 'chained log example', + state: 'passed', + group: groupId, + }) + + cy.get('.command-name-within') + .find('.command-expander') + .should('have.class', 'command-expander-is-open') + + cy.get('.command-name-within2') + .find('.command-expander') + .should('have.class', 'command-expander-is-open') + .click() + + cy.percySnapshot() + }) + }) + + context('mousing over', () => { + beforeEach(() => { + cy.spy(runner, 'emit') + cy.clock() + cy.get('.command-wrapper').first().trigger('mouseover') + }) + + it('shows snapshot after 50ms passes', () => { + cy.wrap(runner.emit).should('not.be.calledWith', 'runner:show:snapshot') + cy.tick(50) + cy.wrap(runner.emit).should('be.calledWith', 'runner:show:snapshot', 1) + cy.wrap(runner.emit).should('be.calledOnce') + }) + + describe('then mousing out', () => { + beforeEach(() => { + cy.tick(50) + cy.get('.command').first().trigger('mouseout') + }) + + it('hides the snapshot after 50ms pass without another mouse over', () => { + cy.tick(50) + cy.wrap(runner.emit).should('be.calledWith', 'runner:hide:snapshot', 1) + }) + + it('does not hide the snapshot if there is another mouseover before 50ms passes', () => { + cy.wrap(runner.emit).should('not.be.calledWith', 'runner:hide:snapshot') + }) + }) + }) + + // FIXME: When studio support is re-introduced we can enable these tests. + context.skip('studio commands', () => { + beforeEach(() => { + addCommand(runner, { + id: 10, + number: 7, + name: 'get', + message: '#studio-command-parent', + state: 'success', + isStudio: true, + type: 'parent', + }) + + addCommand(runner, { + id: 11, + name: 'click', + message: '#studio-command-child', + state: 'success', + isStudio: true, + type: 'child', + }) + }) + + it('studio commands have command-is-studio class', () => { + cy.contains('#studio-command-parent').closest('.command') + .should('have.class', 'command-is-studio') + + cy.contains('#studio-command-child').closest('.command') + .should('have.class', 'command-is-studio') + }) + + it('only parent studio commands display remove button', () => { + cy.contains('#studio-command-parent').closest('.command') + .find('.studio-command-remove').should('be.visible') + + cy.contains('#studio-command-child').closest('.command') + .find('.studio-command-remove').should('not.be.visible') + }) + + it('emits studio:remove:command with number when delete button is clicked', () => { + cy.spy(runner, 'emit') + + cy.contains('#studio-command-parent').closest('.command') + .find('.studio-command-remove').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:remove:command', 7) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/header.cy.ts b/packages/reporter/cypress/e2e/header.cy.ts new file mode 100755 index 0000000000..eea95f0936 --- /dev/null +++ b/packages/reporter/cypress/e2e/header.cy.ts @@ -0,0 +1,231 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from '../../src/runnables/runnables-store' + +const { _ } = Cypress + +describe('header', () => { + let runner: EventEmitter + let runnables: RootRunnable + + beforeEach(() => { + cy.fixture('runnables').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + }) + + describe('tests button', () => { + it('displays tooltip on mouseover', () => { + cy.get('.toggle-specs-wrapper').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Collapse Specs List F') + }) + + it('emits save state on click', () => { + cy.spy(runner, 'emit') + // { force: true } is necessary for click to work, apparently because + // of the tooltip popping up and getting in the way + cy.get('.toggle-specs-wrapper button').click({ force: true }) + cy.wrap(runner.emit).should('be.calledWith', 'save:state') + }) + + it('shows \'Tests\' when >= 398px wide', () => { + cy.get('.toggle-specs-wrapper span').should('be.visible') + }) + }) + + describe('stats', () => { + let addStat: Function + + beforeEach(() => { + addStat = (state: string, times: number) => { + _.times(times, () => { + runner.emit('test:after:run', { state, final: true }) + }) + } + }) + + it('displays numbers for passed, failed, and pending tests', () => { + addStat('passed', 2) + addStat('failed', 3) + addStat('pending', 1) + + cy.get('.passed .num').should('have.text', '2') + cy.get('.failed .num').should('have.text', '3') + cy.get('.pending .num').should('have.text', '1') + + // ensure the page is loaded before taking snapshot + cy.contains('test 4').should('be.visible') + cy.percySnapshot() + }) + + it('displays "--" if zero of the given state', () => { + cy.get('.passed .num').should('have.text', '--') + cy.get('.failed .num').should('have.text', '--') + cy.get('.pending .num').should('have.text', '--') + }) + }) + + describe('controls', () => { + describe('when running, not paused, and/or without next command', () => { + beforeEach(() => { + runner.emit('run:start') + }) + + describe('preferences menu', () => { + it('can be toggled', () => { + cy.get('.testing-preferences').should('not.exist') + cy.get('.testing-preferences-toggle').should('not.have.class', 'open') + cy.get('.testing-preferences-toggle').click() + cy.get('.testing-preferences-toggle').should('have.class', 'open') + cy.get('.testing-preferences').should('be.visible') + cy.get('.testing-preferences-toggle').click() + cy.get('.testing-preferences-toggle').should('not.have.class', 'open') + cy.get('.testing-preferences').should('not.exist') + }) + + it('has tooltip', () => { + cy.get('.testing-preferences-toggle').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Open Testing Preferences') + }) + + it('shows when auto-scrolling is enabled and can disable it', () => { + const switchSelector = '[data-cy=auto-scroll-switch]' + + cy.get('.testing-preferences-toggle').click() + cy.get(switchSelector).invoke('attr', 'aria-checked').should('eq', 'true') + cy.get(switchSelector).click() + cy.get(switchSelector).invoke('attr', 'aria-checked').should('eq', 'false') + }) + + it('can be toggled with shortcut', () => { + const switchSelector = '[data-cy=auto-scroll-switch]' + + cy.get('.testing-preferences-toggle').click() + cy.get(switchSelector).invoke('attr', 'aria-checked').should('eq', 'true') + cy.get('body').type('a').then(() => { + cy.get(switchSelector).invoke('attr', 'aria-checked').should('eq', 'false') + }) + }) + + it('the auto-scroll toggle emits save:state event when clicked', () => { + cy.spy(runner, 'emit') + cy.get('.testing-preferences-toggle').click() + cy.get('[data-cy=auto-scroll-switch]').click() + cy.wrap(runner.emit).should('be.calledWith', 'save:state') + cy.percySnapshot() + }) + }) + + describe('stop button', () => { + it('displays stop button', () => { + cy.get('.stop').should('be.visible') + }) + + it('displays tooltip', () => { + cy.get('.stop').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Stop Running S') + }) + + it('emits runner:stop when clicked', () => { + cy.spy(runner, 'emit') + cy.get('.stop').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:stop') + }) + }) + + describe('pause controls', () => { + it('does not display play button', () => { + cy.get('.play').should('not.exist') + }) + + it('does not display restart button', () => { + cy.get('.restart').should('not.exist') + }) + + it('does not display next button', () => { + cy.get('.next').should('not.exist') + }) + }) + }) + + describe('when paused with next command', () => { + beforeEach(() => { + runner.emit('paused', 'find') + }) + + it('displays play button', () => { + cy.get('.play').should('be.visible') + }) + + it('displays tooltip for play button', () => { + cy.get('.play').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Resume C') + }) + + it('emits runner:resume when play button is clicked', () => { + cy.spy(runner, 'emit') + cy.get('.play').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:resume') + }) + + it('displays next button', () => { + cy.get('.next').should('be.visible') + }) + + it('displays tooltip for next button', () => { + cy.get('.next').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', `Next [N]:find`) + }) + + it('emits runner:next when next button is clicked', () => { + cy.spy(runner, 'emit') + cy.get('.next').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:next') + }) + + it('does not display stop button', () => { + cy.get('.stop').should('not.exist') + }) + }) + + describe('when not running', () => { + it('displays restart button', () => { + cy.get('.restart').should('be.visible') + }) + + it('displays tooltip for restart button', () => { + cy.get('.restart').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Run All Tests R') + }) + + it('emits runner:restart when restart button is clicked', () => { + cy.spy(runner, 'emit') + cy.get('.restart').click() + cy.wrap(runner.emit).should('be.calledWith', 'runner:restart') + }) + + it('does not display stop button', () => { + cy.get('.stop').should('not.exist') + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/hooks.cy.ts b/packages/reporter/cypress/e2e/hooks.cy.ts new file mode 100644 index 0000000000..7a34047a65 --- /dev/null +++ b/packages/reporter/cypress/e2e/hooks.cy.ts @@ -0,0 +1,272 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from '../../src/runnables/runnables-store' +import { addCommand, itHandlesFileOpening } from '../support/utils' + +describe('hooks', () => { + let runner: EventEmitter + let runnables: RootRunnable + + beforeEach(() => { + cy.fixture('runnables_hooks').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + }) + + describe('general behavior', () => { + beforeEach(() => { + cy.contains('test 1').click() + }) + + it('assigns commands to the correct hook', () => { + cy.contains('before each').closest('.collapsible').find('.command').should('have.length', 2) + cy.contains('before each').closest('.collapsible').should('contain', 'http://localhost:3000') + cy.contains('before each').closest('.collapsible').should('contain', '.wrapper') + + cy.contains('test body').closest('.collapsible').find('.command').should('have.length', 1) + cy.contains('test body').closest('.collapsible').should('contain', '.body') + + cy.contains('after each').closest('.collapsible').find('.command').should('have.length', 1) + cy.contains('after each').closest('.collapsible').should('contain', '.cleanup') + cy.percySnapshot() + }) + + it('displays hooks in the correct order', () => { + const hooks = ['before each', 'test body', 'after each'] + + cy.contains('test 1').closest('.runnable').find('.hook-name').each(($name, i) => { + cy.wrap($name).should('contain', hooks[i]) + }) + }) + + it('displays (failed) next to name for failed hooks', () => { + const err = { + name: 'CypressError', + message: 'Could not find element', + stack: 'Could not find element\n at foo (bar.js:1:2)', + } + + runner.emit('test:after:run', { state: 'failed', id: 'r6', failedFromHookId: 'h3', err }) + + cy.contains('test 2').closest('.runnable').contains('before each') + .find('.hook-failed-message') + .should('be.visible') + }) + + it('does not display (failed) next to name for passed hooks', () => { + cy.contains('test 1').closest('.runnable').contains('before each') + .find('.hook-failed-message') + .should('not.be.visible') + }) + + describe('expanding/collapsing', () => { + it('is expanded by default', () => { + cy.contains('before each').closest('.collapsible').find('.commands-container') + .should('be.visible') + }) + + it('collapses on click', () => { + cy.contains('before each').click() + .closest('.collapsible').find('.commands-container') + .should('not.exist') + }) + + it('expands on second click', () => { + cy.contains('before each').click().click() + .closest('.collapsible').find('.commands-container') + .should('be.visible') + }) + }) + }) + + describe('duplicate hooks', () => { + beforeEach(() => { + cy.contains('test 3').click() + }) + + it('splits different hooks with the same name', () => { + cy.contains('before all (1)').closest('.collapsible').find('.command').should('have.length', 1) + cy.contains('before all (1)').closest('.collapsible').should('contain', 'before1') + + cy.contains('before all (2)').closest('.collapsible').find('.command').should('have.length', 1) + cy.contains('before all (2)').closest('.collapsible').should('contain', 'before2') + + cy.contains('before each (1)').closest('.collapsible').find('.command').should('have.length', 2) + cy.contains('before each (1)').closest('.collapsible').should('contain', 'http://localhost:3000') + cy.contains('before each (1)').closest('.collapsible').should('contain', '.wrapper') + + cy.contains('before each (2)').closest('.collapsible').find('.command').should('have.length', 1) + cy.contains('before each (2)').closest('.collapsible').should('contain', '.header') + }) + + it('does not display hook number when only one', () => { + cy.get('.hooks-container').should('contain', 'after each') + cy.get('.hooks-container').should('not.contain', 'after each (1)') + }) + }) + + describe('open hooks in IDE', () => { + beforeEach(() => { + cy.contains('test 1').click() + }) + + it('does not display button without hover', () => { + cy.contains('Open in IDE').should('not.be.visible') + }) + + it('creates button when hook has invocation details', () => { + cy.contains('before each').closest('.hook-header').should('contain', 'Open in IDE') + }) + + it('creates button when test has invocation details', () => { + cy.contains('test body').closest('.hook-header').should('contain', 'Open in IDE') + }) + + it('does not create button when hook does not have invocation details', () => { + cy.contains('after each').closest('.hook-header').should('not.contain', 'Open in IDE') + }) + + describe('handles file opening', () => { + beforeEach(() => { + cy.get('.hook-open-in-ide').first().invoke('show') + }) + + itHandlesFileOpening({ + getRunner: () => runner, + selector: '.hook-open-in-ide', + file: { + file: '/absolute/path/to/foo_spec.js', + column: 4, + line: 10, + }, + }) + }) + }) + + describe('studio hook', () => { + it('is not visible when not in studio mode', () => { + cy.contains('test 1').click() + + cy.contains('studio commands').should('not.exist') + }) + + describe('with studio active', () => { + beforeEach(() => { + runner.emit('reporter:start', { studioActive: true }) + + cy.contains('test 1').click() + }) + + it('is visible with hook-studio class', () => { + cy.contains('studio commands').should('exist') + .closest('.hook-item').should('have.class', 'hook-studio') + + cy.percySnapshot() + }) + + it('is not visible if test failed', () => { + cy.contains('test 2').closest('.test') + .contains('studio commands').should('not.exist') + }) + + describe('prompt', () => { + it('displays by default and disappears once commands are added', () => { + cy.get('.hook-studio').find('.studio-prompt').should('exist').then(() => { + addCommand(runner, { + id: 1, + hookId: 'r3-studio', + number: 1, + name: 'get', + message: '#studio-command-parent', + state: 'success', + isStudio: true, + type: 'parent', + }) + + addCommand(runner, { + id: 2, + hookId: 'r3-studio', + name: 'click', + message: '#studio-command-child', + state: 'success', + isStudio: true, + type: 'child', + }) + + cy.get('.hook-studio').find('.studio-prompt').should('not.exist') + }) + }) + + it('displays when there is only a visit command and disappears once additional commands are added', () => { + addCommand(runner, { + id: 1, + hookId: 'r3-studio', + number: 1, + name: 'visit', + message: 'the://url', + state: 'success', + type: 'parent', + }) + + cy.get('.hook-studio').find('.studio-prompt').should('exist').then(() => { + addCommand(runner, { + id: 2, + hookId: 'r3-studio', + number: 2, + name: 'get', + message: '#studio-command-parent', + state: 'success', + isStudio: true, + type: 'parent', + }) + + addCommand(runner, { + id: 3, + hookId: 'r3-studio', + name: 'click', + message: '#studio-command-child', + state: 'success', + isStudio: true, + type: 'child', + }) + + cy.get('.hook-studio').find('.studio-prompt').should('not.exist') + }) + }) + + it('does not display when a failed visit command is added', () => { + addCommand(runner, { + id: 1, + hookId: 'r3-studio', + number: 1, + name: 'visit', + message: 'the://url', + state: 'failed', + type: 'parent', + }) + + cy.get('.hook-studio').find('.studio-prompt').should('not.exist') + }) + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/meta_&%.cy.ts b/packages/reporter/cypress/e2e/meta_&%.cy.ts new file mode 100644 index 0000000000..9afdea03c8 --- /dev/null +++ b/packages/reporter/cypress/e2e/meta_&%.cy.ts @@ -0,0 +1,9 @@ +// this ensures that special characters in the spec title are displayed +// properly. it tests the actual reporter instead of the AUT like other tests +describe('special characters', () => { + it('displays file name with decoded special characters', () => { + cy.wrap(Cypress.$(window.top.document.body)) + .find('.reporter .runnable-header a') + .should('have.text', 'meta_&%.cy.ts') + }) +}) diff --git a/packages/reporter/cypress/e2e/routes.cy.ts b/packages/reporter/cypress/e2e/routes.cy.ts new file mode 100644 index 0000000000..6dc588a729 --- /dev/null +++ b/packages/reporter/cypress/e2e/routes.cy.ts @@ -0,0 +1,130 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from './../../src/runnables/runnables-store' + +describe('routes', () => { + let runner: EventEmitter + let runnables: RootRunnable + let start: Function + + beforeEach(() => { + cy.fixture('runnables_routes').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + }) + }) + + start = () => { + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + + cy.contains('http://localhost:3000') // ensure test content has loaded + } + }) + + it('does not display if there are no routes', () => { + runnables.tests![0].routes = [] + start() + cy.get('.runnable-routes-region').should('not.be.visible') + }) + + describe('when there are routes', () => { + beforeEach(() => { + start() + }) + + it('displays header with number of routes', () => { + cy.contains('Routes (3)').should('be.visible') + }) + + it('is collapsed by default', () => { + cy.contains('Routes (3)').closest('.runnable-routes-region').find('table') + .should('not.exist') + }) + + it('expands on click', () => { + cy.contains('Routes (3)').click() + cy.contains('Routes (3)').closest('.runnable-routes-region').find('table') + .should('be.visible') + + cy.percySnapshot() + }) + }) + + describe('when routes are expanded', () => { + beforeEach(() => { + start() + cy.contains('Routes (3)').click() + }) + + it('displays tooltip for number of routes', () => { + cy.get('.runnable-routes-region').contains('#').trigger('mouseover') + cy.get('.cy-tooltip') + .should('have.text', 'Number of responses which matched this route') + }) + + it('route displays without no-responses class if numResponses is non-zero', () => { + cy.get('.route-item').first() + .should('not.have.class', 'no-responses') + }) + + it('route displays with no-responses class if zero numResponses', () => { + cy.get('.route-item').eq(1) + .should('have.class', 'no-responses') + }) + + it('route displays the method', () => { + cy.get('.route-item .route-method').first() + .should('have.text', 'GET') + }) + + it('route displays the url', () => { + cy.get('.route-item .route-url').first() + .should('have.text', '/posts') + }) + + it('route displays isStubbed as Yes if stubbed', () => { + cy.get('.route-item .route-is-stubbed').eq(1) + .should('have.text', 'Yes') + }) + + it('route displays isStubbed as No if not stubbed', () => { + cy.get('.route-item .route-is-stubbed').first() + .should('have.text', 'No') + }) + + it('route displays the alias', () => { + cy.get('.route-item .route-alias-name').eq(2) + .should('have.text', 'createPost') + }) + + it('route displays a Tooltip for the alias', () => { + cy.get('.route-item .route-alias-name').eq(2).trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', `Aliased this route as: 'createPost'`) + }) + + it('route displays the numResponses if non-zero', () => { + cy.get('.route-item .route-num-responses').first() + .should('have.text', '2') + }) + + it('route displays the numResponses as "-" if zero', () => { + cy.get('.route-item .route-num-responses').eq(1) + .should('have.text', '-') + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/runnables.cy.ts b/packages/reporter/cypress/e2e/runnables.cy.ts new file mode 100644 index 0000000000..816a5523aa --- /dev/null +++ b/packages/reporter/cypress/e2e/runnables.cy.ts @@ -0,0 +1,235 @@ +import { EventEmitter } from 'events' +import { RunnablesErrorModel } from '../../src/runnables/runnable-error' +import { RootRunnable } from '../../src/runnables/runnables-store' +import { itHandlesFileOpening } from '../support/utils' + +interface RenderProps { + error?: RunnablesErrorModel +} + +describe('runnables', () => { + let runner: EventEmitter + let runnables: RootRunnable + let render: Function + let start: Function + + beforeEach(() => { + cy.fixture('runnables').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + render = (renderProps: RenderProps = {}) => { + cy.visit('/').then((win) => { + win.render(Object.assign({ + runner, + runnerStore: { + spec: { + name: 'foo', + absolute: '/foo/bar', + relative: 'foo/bar', + }, + }, + experimentalStudioEnabled: true, + }, renderProps)) + }) + } + + start = (renderProps?: RenderProps) => { + render(renderProps) + + return cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + } + }) + + it('displays loader when runnables have not yet loaded', () => { + render() + cy.contains('Your tests are loading...').should('be.visible') + // ensure the page is loaded before taking snapshot + cy.percySnapshot() + }) + + it('displays runnables when they load', () => { + start() + cy.get('.runnable').should('have.length', 9) + cy.contains('test 4').should('be.visible') + + cy.percySnapshot() + }) + + it('displays bundle error if specified', () => { + const error = { + title: 'Oops...we found an error preparing this test file:', + link: 'https://on.cypress.io/we-found-an-error-preparing-your-test-file', + callout: '/path/to/spec', + message: 'We found an error', + } + + start({ error }) + + cy.contains(error.title) + cy.contains(error.callout) + cy.contains(error.message) + + cy.get('.error a').should('have.attr', 'href', error.link) + cy.get('.error a').should('have.attr', 'target', '_blank') + }) + + it('error does not render link if there is not one specified', () => { + const error = { + title: 'Oops...we found an error preparing this test file:', + callout: '/path/to/spec', + message: 'We found an error', + } + + start({ error }) + cy.get('.error a').should('not.exist') + }) + + it('error does not display callout if there is not one specified', () => { + const error = { + title: 'Oops...we found an error preparing this test file:', + message: 'We found an error', + } + + start({ error }) + cy.get('.error pre').should('not.exist') + }) + + it('error displays message with markdown', () => { + const error = { + title: 'Oops...we found an error preparing this test file:', + message: `We **found** an _error_: + + - fix + - it +`, + } + + start({ error }) + cy.get('.error strong').should('have.text', 'found') + cy.get('.error em').should('have.text', 'error') + cy.get('.error li').should('have.length', 2) + }) + + it('displays the time taken in seconds', () => { + start() + + const startTime = new Date(2000, 0, 1) + const now = new Date(2000, 0, 1, 0, 0, 12, 340) + + cy.clock(now).then(() => { + runner.emit('reporter:start', { startTime: startTime.toISOString() }) + }) + + cy.get('.runnable-header span:last').should('have.text', '00:12') + }) + + it('does not display time if no time taken', () => { + start() + cy.get('.runnable-header span:first').should('have.text', 'foo') + cy.get('.runnable-header span:last').should('not.have.text', '--') + }) + + describe('when there are no tests', () => { + beforeEach(() => { + runnables.suites = [] + }) + + it('displays error', () => { + start() + + cy.contains('No tests found.').should('be.visible') + cy.contains('Cypress could not detect tests in this file.').should('be.visible') + cy.contains('Open file in IDE').should('be.visible') + cy.contains('Create test with Cypress Studio').should('be.visible') + cy.get('.help-link').should('have.attr', 'href', 'https://on.cypress.io/intro') + cy.get('.help-link').should('have.attr', 'target', '_blank') + cy.percySnapshot() + }) + + it('does not display links to work with file if running all specs', () => { + start({ + runnerStore: { + spec: { + name: 'All Integration Specs', + absolute: '__all', + relative: '__all', + }, + }, + }) + + cy.contains('No tests found.').should('be.visible') + cy.contains('Cypress could not detect tests in this file.').should('be.visible') + cy.contains('Open file in IDE').should('not.exist') + cy.contains('Create test with Cypress Studio').should('not.exist') + cy.get('.help-link').should('have.attr', 'href', 'https://on.cypress.io/intro') + cy.get('.help-link').should('have.attr', 'target', '_blank') + }) + + it('can launch studio', () => { + start().then(() => { + cy.stub(runner, 'emit') + + cy.contains('Cypress Studio').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:init:suite', 'r1') + }) + }) + + describe('open in ide', () => { + beforeEach(() => { + start({ + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + }) + }) + + itHandlesFileOpening({ + getRunner: () => runner, + selector: '.no-tests a', + file: { + file: '/absolute/path/to/foo.js', + line: 0, + column: 0, + }, + }) + }) + }) + + describe('runnable-header (unified)', () => { + beforeEach(() => { + cy.window().then((win) => win.__vite__ = true) + + start({ + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + }) + }) + + it('contains name of spec and emits when clicked', () => { + const selector = '.runnable-header a' + + cy.stub(runner, 'emit').callThrough() + + cy.get(selector).as('spec-title').contains('foo.js') + cy.get(selector).click().then(() => { + expect(runner.emit).to.be.calledWith('open:file:unified') + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/shortcuts.cy.ts b/packages/reporter/cypress/e2e/shortcuts.cy.ts new file mode 100755 index 0000000000..afd8e98bdc --- /dev/null +++ b/packages/reporter/cypress/e2e/shortcuts.cy.ts @@ -0,0 +1,165 @@ +import sinon, { SinonStub, SinonSpy } from 'sinon' +import { EventEmitter } from 'events' + +type EventEmitterStub = EventEmitter & Stub + +interface Stub { + on: SinonStub + emit: SinonSpy +} + +const runnerStub = () => { + return { + on: sinon.stub(), + emit: sinon.spy(), + } as EventEmitterStub +} + +describe('shortcuts', function () { + let runner: EventEmitterStub + + beforeEach(function () { + runner = runnerStub() + + cy.fixture('runnables').as('runnables') + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', this.runnables) + runner.emit('reporter:start', {}) + }) + }) + + describe('shortcuts', () => { + it('stops tests', () => { + cy.get('body').then(() => { + expect(runner.emit).not.to.have.been.calledWith('runner:stop') + }) + + cy.get('body').type('s').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:stop') + }) + }) + + it('does not stop tests when paused', () => { + cy.get('body').then(() => { + expect(runner.emit).not.to.have.been.calledWith('runner:stop') + }) + + runner.on.withArgs('paused').callArgWith(1, 'next command') + + cy.get('body').type('s').then(() => { + expect(runner.emit).not.to.have.been.calledWith('runner:stop') + }) + }) + + it('resumes tests', () => { + cy.get('body').then(() => { + expect(runner.emit).not.to.have.been.calledWith('runner:restart') + }) + + cy.get('body').type('r').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:restart') + }) + }) + + it('toggles the specs list', () => { + // 1. save:state should be emitted to preserve the change in state + // 2. the reporter appSate should be also be updated with the new value, + // checking the aria-expanded state of the button confirms this + + cy.get('body').then(() => { + expect(runner.emit).not.to.have.been.calledWith('save:state') + cy.contains('button', 'Specs').should('have.attr', 'aria-expanded', 'true') + }) + + cy.get('body').type('f').then(() => { + expect(runner.emit).to.have.been.calledWith('save:state') + cy.contains('button', 'Specs').should('have.attr', 'aria-expanded', 'false') + }) + + cy.get('body').type('f').then(() => { + expect(runner.emit).to.have.been.calledWith('save:state') + cy.contains('button', 'Specs').should('have.attr', 'aria-expanded', 'true') + }) + }) + + it('continues resuming tests', () => { + cy.get('body').type('s').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:stop') + }) + + cy.get('body').type('c').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:resume') + }) + }) + + it('go to next test', () => { + cy.get('body').type('s').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:stop') + }) + + cy.get('body').type('n').then(() => { + expect(runner.emit).to.have.been.calledWith('runner:next') + }) + }) + + it('toggles auto-scrolling', () => { + cy.get('body').type('a') + cy.get('.testing-preferences-toggle').click() + cy.get('[data-cy=auto-scroll-switch]').invoke('attr', 'aria-checked').should('eq', 'false') + cy.get('.testing-preferences-toggle').click() + cy.get('body').type('a') + cy.get('.testing-preferences-toggle').click() + cy.get('[data-cy=auto-scroll-switch]').invoke('attr', 'aria-checked').should('eq', 'true') + }) + + it('does not run shortcut if typed into an input', () => { + cy.get('body') + .then(($body) => { + // this realistically happens with the selector playground, but + // need to add an input since this environment is isolated + $body.append('') + }) + .get('#temp-input').type('r', { force: true }) + .then(() => { + expect(runner.emit).not.to.have.been.calledWith('runner:restart') + }) + }) + + it('has shortcut in tooltips', () => { + cy.get('.toggle-specs-wrapper > button').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Collapse Specs List F') + cy.get('.toggle-specs-wrapper > button').trigger('mouseout') + + cy.get('button.restart').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Run All Tests R') + + cy.window().then((win) => win.state.isRunning = true) + cy.get('button.stop').trigger('mouseover') + cy.get('.cy-tooltip').should('have.text', 'Stop Running S') + }) + + it('does not run shortcut if modifier keys are pressed', () => { + ['{ctrl+f}', '{alt+f}', '{shift+f}', '{meta+f}'].forEach((text) => { + cy.get('body').type(text) + }) + + cy.then(() => { + expect(runner.emit).not.to.have.been.calledWith('focus:tests') + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/spec_title.cy.ts b/packages/reporter/cypress/e2e/spec_title.cy.ts new file mode 100644 index 0000000000..07520189a1 --- /dev/null +++ b/packages/reporter/cypress/e2e/spec_title.cy.ts @@ -0,0 +1,78 @@ +import { EventEmitter } from 'events' +import { itHandlesFileOpening } from '../support/utils' + +describe('spec title', () => { + let runner: EventEmitter + let start: Function + + beforeEach(() => { + runner = new EventEmitter() + + start = (spec: Cypress.Cypress['spec']) => { + cy.visit('/').then((win) => { + win.render({ runner, runnerStore: { spec } }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', {}) + runner.emit('reporter:start', {}) + }) + } + }) + + it('all specs displays "All Specs"', () => { + start({ + relative: '__all', + name: '', + absolute: '__all', + }) + + cy.get('.runnable-header').should('have.text', 'All Specs') + + cy.percySnapshot() + }) + + it('all specs displays "Specs matching ..."', () => { + start({ + relative: '__all', + name: '', + absolute: '__all', + specFilter: 'cof', + }) + + cy.contains('.runnable-header', 'Specs matching "cof"') + + cy.percySnapshot() + }) + + describe('single spec', () => { + beforeEach(() => { + start({ + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }) + }) + + it('displays name without path', () => { + cy.get('.runnable-header').find('a').should('have.text', 'foo.js') + + cy.percySnapshot() + }) + + it('displays tooltip on hover', () => { + cy.get('.runnable-header a').first().trigger('mouseover') + cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') + }) + + itHandlesFileOpening({ + getRunner: () => runner, + selector: '.runnable-header a', + file: { + file: '/absolute/path/to/foo.js', + line: 0, + column: 0, + }, + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/suites.cy.ts b/packages/reporter/cypress/e2e/suites.cy.ts new file mode 100644 index 0000000000..bae838845a --- /dev/null +++ b/packages/reporter/cypress/e2e/suites.cy.ts @@ -0,0 +1,163 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from '../../src/runnables/runnables-store' + +describe('suites', () => { + let runner: EventEmitter + let runnables: RootRunnable + + beforeEach(() => { + cy.fixture('runnables').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + experimentalStudioEnabled: true, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + }) + + it('includes the class "suite"', () => { + cy.contains('suite 1') + .closest('.runnable') + .should('have.class', 'suite') + + // ensure the page is loaded before taking snapshot + cy.contains('test 4').should('be.visible') + cy.percySnapshot() + }) + + it('includes the state as a class', () => { + cy.contains('suite 1') + .closest('.runnable') + .should('have.class', 'runnable-failed') + + cy.contains('suite 2') + .closest('.runnable') + .should('have.class', 'runnable-passed') + }) + + describe('expand and collapse', () => { + it('is expanded by default', () => { + cy.contains('suite 1') + .parents('.collapsible').as('suiteWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('be.visible') + }) + + describe('expand/collapse suite manually', () => { + beforeEach(() => { + cy.contains('suite 1') + .parents('.collapsible').as('suiteWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content') + .should('be.visible') + }) + + it('expands/collapses on click', () => { + cy.contains('suite 1') + .click() + + cy.get('@suiteWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('not.be.visible') + + cy.contains('suite 1') + .click() + + cy.get('@suiteWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('be.visible') + }) + + it('expands/collapses on enter', () => { + cy.contains('suite 1') + .parents('.collapsible-header') + .focus().type('{enter}') + + cy.get('@suiteWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('not.be.visible') + + cy.contains('suite 1') + .parents('.collapsible-header') + .focus().type('{enter}') + + cy.get('@suiteWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('be.visible') + }) + + it('expands/collapses on space', () => { + cy.contains('suite 1') + .parents('.collapsible-header') + .focus().type(' ') + + cy.get('@suiteWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('not.be.visible') + + cy.contains('suite 1') + .parents('.collapsible-header') + .focus().type(' ') + + cy.get('@suiteWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').eq(0) + .should('be.visible') + }) + }) + }) + + describe('studio button', () => { + it('displays studio icon with half transparency when hovering over test title', () => { + cy.contains('nested suite 1') + .closest('.runnable-wrapper') + .realHover() + .find('.runnable-controls-studio') + .should('be.visible') + .should('have.css', 'opacity', '0.5') + }) + + it('displays studio icon with no transparency and tooltip on hover', () => { + cy.contains('nested suite 1') + .closest('.collapsible-header') + .find('.runnable-controls-studio') + .realHover() + .should('be.visible') + .should('have.css', 'opacity', '1') + + cy.get('.cy-tooltip').contains('Add New Test') + }) + + it('emits studio:init:suite with the suite id when clicked', () => { + cy.stub(runner, 'emit') + + cy.contains('suite 1').parents('.collapsible-header') + .find('.runnable-controls-studio').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:init:suite', 'r2') + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/test_errors.cy.ts b/packages/reporter/cypress/e2e/test_errors.cy.ts new file mode 100644 index 0000000000..bc9e073730 --- /dev/null +++ b/packages/reporter/cypress/e2e/test_errors.cy.ts @@ -0,0 +1,311 @@ +import { EventEmitter } from 'events' +import { itHandlesFileOpening } from '../support/utils' +import Err from '../../src/errors/err-model' +import { RootRunnable } from '../../src/runnables/runnables-store' + +describe('test errors', () => { + let commandErr: Partial + let setError: Function + let runnablesWithErr: RootRunnable + let runner: EventEmitter + + beforeEach(() => { + cy.fixture('runnables_error').then((_runnablesWithErr) => runnablesWithErr = _runnablesWithErr) + cy.fixture('command_error').then((_commandErr) => commandErr = _commandErr) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + setError = (err: Error) => { + // @ts-ignore + runnablesWithErr.suites[0].tests[0].err = err + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnablesWithErr) + runner.emit('reporter:start', {}) + }) + } + + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + }) + }) + }) + + describe('print to console', () => { + beforeEach(() => { + setError(commandErr) + }) + + it('clicking prints to console', () => { + cy.spy(runner, 'emit') + cy.get('.runnable-err-print').click().should(() => { + expect(runner.emit).to.be.calledWith('runner:console:error') + + // @ts-ignore + const err = runner.emit.withArgs('runner:console:error').lastCall.args[1].err + + expect(err.message).to.equal(commandErr.message) + expect(err.stack).to.equal(commandErr.stack) + }) + }) + + it('shows popup confirming output was printed', () => { + cy.get('.runnable-err-print').click() + cy.contains('Printed output to your console') + }) + + it('does not collapse test when clicking', () => { + cy.get('.runnable-err-print').click() + cy.get('.command-wrapper').should('be.visible') + }) + + it('does not expand or collapse stack trace when clicking', () => { + cy.get('.runnable-err-print').click() + cy.get('.runnable-err-stack-trace').should('not.be.visible') + cy.contains('View stack trace').click() + cy.get('.runnable-err-stack-trace').should('be.visible') + cy.get('.runnable-err-print').click() + cy.get('.runnable-err-stack-trace').should('be.visible') + }) + }) + + describe('stack trace', () => { + beforeEach(() => { + setError(commandErr) + }) + + it('hides stack trace by default', () => { + cy.get('.runnable-err-stack-trace').should('not.be.visible') + }) + + it('opens stack trace on click', () => { + cy.contains('View stack trace').click() + cy.get('.runnable-err-stack-trace').should('be.visible') + cy.percySnapshot() + }) + + it('pairs down stack line whitespace', () => { + cy.contains('View stack trace').click() + + cy.get('.runnable-err-stack-trace').within(() => { + cy.get('.err-stack-line') + .should('have.length', 10) + .first().should('have.text', 'at foo.bar (my/app.js:2:7)') + + cy.get('.err-stack-line') + .eq(1).should('have.text', ' at baz.qux (cypress/integration/foo_spec.js:5:2)') + + cy.get('.err-stack-line') + .eq(2).should('have.text', ' at space (cypress/integration/a b.js:34:99)') + + cy.get('.err-stack-line') + .eq(3).should('have.text', 'At previous event:') + + cy.get('.err-stack-line') + .eq(4).should('have.text', ' at bar.baz (http://localhost:1234/me/dev/my/app.js:8:11)') + + cy.get('.err-stack-line') + .eq(5).should('have.text', ' at callFn (cypress://../driver/src/cypress/runner.js:9:12)') + }) + }) + + it('does not include message in stack trace', () => { + cy.contains('View stack trace').click() + cy.get('.runnable-err-stack-trace') + .invoke('text') + .should('not.include', 'Some Error') + .should('not.include', 'Message line below blank line') + }) + + it('turns files into links', () => { + cy.contains('View stack trace').click() + + cy.get('.runnable-err-stack-trace .runnable-err-file-path') + .should('have.length', 3) + .first() + .should('have.text', 'my/app.js:2:7') + + cy.get('.runnable-err-stack-trace .runnable-err-file-path').eq(1) + .should('have.text', 'cypress/integration/foo_spec.js:5:2') + + cy.get('.runnable-err-stack-trace .runnable-err-file-path').eq(2) + .should('have.text', 'cypress/integration/a b.js:34:99') + }) + + it('does not turn cypress:// files into links', () => { + cy.contains('View stack trace').click() + cy.contains('cypress://').find('a').should('not.exist') + }) + + it('does not turn cypress_runner.js files into links', () => { + cy.contains('View stack trace').click() + cy.contains('cypress_runner.js').find('a').should('not.exist') + }) + + it('does not turn lines without absoluteFile into links', () => { + cy.contains('View stack trace').click() + cy.contains('.err-stack-line', 'http://localhost:1234/me/dev/my/app.js:8:11') + .find('a').should('not.exist') + }) + + it('does not turn anything after "From Node.js Internals" into links', () => { + cy.contains('View stack trace').click() + cy.contains('events.js').find('a').should('not.exist') + cy.contains('node/internals.js').find('a').should('not.exist') + }) + + it('does not collapse test when clicking', () => { + cy.contains('View stack trace').click() + cy.get('.command-wrapper').should('be.visible') + }) + + it('displays tooltip on hover', () => { + cy.contains('View stack trace').click() + + cy.get('.runnable-err-stack-trace a').first().trigger('mouseover') + cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') + }) + + itHandlesFileOpening({ + getRunner: () => runner, + selector: '.runnable-err-stack-trace a', + file: { + file: '/me/dev/my/app.js', + line: 2, + column: 7, + }, + stackTrace: true, + }) + }) + + describe('command error', () => { + it('shows error name', () => { + setError(commandErr) + + cy.get('.runnable-err-name').should('contain', commandErr.name) + }) + + it('renders and escapes markdown', () => { + setError(commandErr) + + cy.get('.runnable-err-message') + + // renders `foo` as foo + .contains('code', 'foo') + .then((content) => { + expect(content).not.to.contain('`foo`') + }) + + // renders /`bar/` as `bar` + cy.get('.runnable-err-message') + .should('contain', '`bar`') + + // renders **baz** as baz + cy.get('.runnable-err-message') + .contains('strong', 'baz') + .then((content) => { + expect(content).not.to.contain('**baz**') + }) + + // renders *fizz* as fizz + cy.get('.runnable-err-message') + .contains('em', 'fizz') + .then((content) => { + expect(content).not.to.contain('*fizz*') + }) + + cy.percySnapshot() + }) + + // NOTE: still needs to be implemented + it.skip('renders and escapes markdown with leading/trailing whitespace', () => { + cy.get('.runnable-err-message') + + // https://github.com/cypress-io/cypress/issues/1360 + // renders ** buzz ** as buzz + .contains('code', 'foo') + .and('not.contain', '`foo`') + }) + }) + + describe('code frames', () => { + beforeEach(() => { + setError(commandErr) + }) + + it('shows code frame when included on error', () => { + cy + .get('.test-err-code-frame') + .should('be.visible') + + cy.percySnapshot() + }) + + it('use correct language class', () => { + cy + .get('.test-err-code-frame pre') + .should('have.class', 'language-javascript') + }) + + it('displays tooltip on hover', () => { + cy.get('.test-err-code-frame a').first().trigger('mouseover') + cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') + }) + + itHandlesFileOpening({ + getRunner: () => runner, + selector: '.test-err-code-frame a', + file: { + file: '/me/dev/my/app.js', + line: 2, + column: 7, + }, + }) + }) + + describe('code frames', () => { + it('does not show code frame when not included on error', () => { + commandErr.codeFrame = undefined + setError(commandErr) + + cy + .get('.test-err-code-frame') + .should('not.exist') + }) + + it('falls back to text language class', () => { + // @ts-ignore + commandErr.codeFrame.language = null + setError(commandErr) + cy + .get('.test-err-code-frame pre') + .should('have.class', 'language-text') + }) + }) + + describe('studio error', () => { + beforeEach(() => { + setError(runnablesWithErr) + }) + + it('is not visible by default', () => { + cy.get('.studio-err-wrapper').should('not.be.visible') + }) + + it('is visible when studio is active', () => { + runner.emit('reporter:start', { studioActive: true }) + + cy.get('.studio-err-wrapper').should('be.visible') + + cy.percySnapshot() + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/tests.cy.ts b/packages/reporter/cypress/e2e/tests.cy.ts new file mode 100644 index 0000000000..eeb62e4266 --- /dev/null +++ b/packages/reporter/cypress/e2e/tests.cy.ts @@ -0,0 +1,311 @@ +import { EventEmitter } from 'events' +import { RootRunnable } from '../../src/runnables/runnables-store' +import { addCommand } from '../support/utils' + +describe('tests', () => { + let runner: EventEmitter + let runnables: RootRunnable + + const addStudioCommand = () => { + addCommand(runner, { + hookId: 'r3-studio', + name: 'get', + message: '#studio-command', + state: 'success', + isStudio: true, + }) + } + + beforeEach(() => { + cy.fixture('runnables').then((_runnables) => { + runnables = _runnables + }) + + runner = new EventEmitter() + + cy.visit('/').then((win) => { + win.render({ + runner, + runnerStore: { + spec: { + name: 'foo.js', + relative: 'relative/path/to/foo.js', + absolute: '/absolute/path/to/foo.js', + }, + }, + experimentalStudioEnabled: true, + }) + }) + + cy.get('.reporter').then(() => { + runner.emit('runnables:ready', runnables) + runner.emit('reporter:start', {}) + }) + }) + + it('includes the class "test"', () => { + cy.contains('test 1') + .closest('.runnable') + .should('have.class', 'test') + }) + + it('includes the state as a class', () => { + cy.contains('suite 1') + .closest('.runnable') + .should('have.class', 'runnable-failed') + + cy.contains('suite 2') + .closest('.runnable') + .should('have.class', 'runnable-passed') + }) + + describe('expand and collapse', () => { + beforeEach(() => { + cy.contains('test 1') + .parents('.collapsible').first().as('testWrapper') + }) + + it('is collapsed by default', () => { + cy.contains('test 1') + .parents('.collapsible').first() + .should('not.have.class', 'is-open') + .find('.collapsible-content') + .should('not.be.visible') + }) + + it('failed tests expands automatically', () => { + cy.contains('test 2') + .parents('.collapsible').first() + .should('have.class', 'is-open') + .find('.collapsible-content') + .should('be.visible') + }) + + it('expands/collapses on click', () => { + cy.contains('test 1') + .click() + + cy.get('@testWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').should('be.visible') + + cy.contains('test 1') + .click() + + cy.get('@testWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').should('not.be.visible') + }) + + it('expands/collapses on enter', () => { + cy.contains('test 1') + .parents('.collapsible-header').first() + .focus().type('{enter}') + + cy.get('@testWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').should('be.visible') + + cy.contains('test 1') + .parents('.collapsible-header').first() + .focus().type('{enter}') + + cy.get('@testWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').should('not.be.visible') + }) + + it('expands/collapses on space', () => { + cy.contains('test 1') + .parents('.collapsible-header').first() + .focus().type(' ') + + cy.get('@testWrapper') + .should('have.class', 'is-open') + .find('.collapsible-content').should('be.visible') + + cy.contains('test 1') + .parents('.collapsible-header').first() + .focus().type(' ') + + cy.get('@testWrapper') + .should('not.have.class', 'is-open') + .find('.collapsible-content').should('not.be.visible') + }) + }) + + // FIXME: When studio support is re-introduced we can enable these tests. + describe.skip('studio', () => { + describe('button', () => { + it('displays studio icon with half transparency when hovering over test title', { scrollBehavior: false }, () => { + cy.contains('test 1') + .closest('.runnable-wrapper') + .realHover() + .find('.runnable-controls-studio') + .should('be.visible') + .should('have.css', 'opacity', '0.5') + }) + + it('displays studio icon with no transparency and tooltip on hover', { scrollBehavior: false }, () => { + cy.contains('test 1') + .closest('.collapsible-header') + .find('.runnable-controls-studio') + .realHover() + .should('be.visible') + .should('have.css', 'opacity', '1') + + cy.get('.cy-tooltip').contains('Add Commands to Test') + }) + + it('emits studio:init:test with the suite id when studio button clicked', () => { + cy.stub(runner, 'emit') + + cy.contains('test 1').parents('.collapsible-header') + .find('.runnable-controls-studio').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:init:test', 'r3') + }) + }) + + describe('controls', () => { + it('is not visible by default', () => { + cy.contains('test 1').click() + .parents('.collapsible').first() + .find('.studio-controls').should('not.exist') + }) + + describe('with studio active', () => { + beforeEach(() => { + runner.emit('reporter:start', { studioActive: true }) + + cy.contains('test 1').click() + .parents('.collapsible').first() + .find('.studio-controls').as('studioControls') + }) + + it('is visible with save and copy button when test passed', () => { + cy.get('@studioControls').should('be.visible') + cy.get('@studioControls').find('.studio-save').should('be.visible') + cy.get('@studioControls').find('.studio-copy').should('be.visible') + + cy.percySnapshot() + }) + + it('is visible without save and copy button if test failed', () => { + cy.contains('test 2') + .parents('.collapsible').first() + .find('.studio-controls').should('be.visible') + + cy.contains('test 2') + .parents('.collapsible').first() + .find('.studio-save').should('not.be.visible') + + cy.contains('test 2') + .parents('.collapsible').first() + .find('.studio-copy').should('not.be.visible') + }) + + it('is visible without save and copy button if test was skipped', () => { + cy.contains('nested suite 1') + .parents('.collapsible').first() + .contains('test 1').click() + .parents('.collapsible').first() + .find('.studio-controls').as('pendingControls') + .should('be.visible') + + cy.get('@pendingControls').find('.studio-save').should('not.be.visible') + cy.get('@pendingControls').find('.studio-copy').should('not.be.visible') + }) + + it('is not visible while test is running', () => { + cy.contains('nested suite 1') + .parents('.collapsible').first() + .contains('test 2').click() + .parents('.collapsible').first() + .find('.studio-controls').should('not.be.visible') + }) + + it('emits studio:cancel when cancel button clicked', () => { + cy.stub(runner, 'emit') + + cy.get('@studioControls').find('.studio-cancel').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:cancel') + }) + + describe('copy button', () => { + it('is disabled without tooltip when there are no commands', () => { + cy.get('@studioControls') + .find('.studio-copy') + .should('be.disabled') + .parent('span') + .trigger('mouseover') + + cy.get('.cy-tooltip').should('not.exist') + }) + + it('is enabled with tooltip when there are commands', () => { + addStudioCommand() + + cy.get('@studioControls') + .find('.studio-copy') + .should('not.be.disabled') + .trigger('mouseover') + + cy.get('.cy-tooltip').should('have.text', 'Copy Commands to Clipboard') + }) + + it('is emits studio:copy:to:clipboard when clicked', () => { + addStudioCommand() + + cy.stub(runner, 'emit') + + cy.get('@studioControls').find('.studio-copy').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:copy:to:clipboard') + }) + + it('displays success state after commands are copied', () => { + addStudioCommand() + + cy.stub(runner, 'emit').callsFake((event, callback) => { + if (event === 'studio:copy:to:clipboard') { + callback('') + } + }) + + cy.get('@studioControls') + .find('.studio-copy') + .click() + .should('have.class', 'studio-copy-success') + .trigger('mouseover') + + cy.get('.cy-tooltip').should('have.text', 'Commands Copied!') + }) + }) + + describe('save button', () => { + it('is disabled without commands', () => { + cy.get('@studioControls').find('.studio-save').should('be.disabled') + }) + + it('is enabled when there are commands', () => { + addStudioCommand() + + cy.get('@studioControls').find('.studio-save').should('not.be.disabled') + }) + + it('is emits studio:save when clicked', () => { + addStudioCommand() + + cy.stub(runner, 'emit') + + cy.get('@studioControls').find('.studio-save').click() + + cy.wrap(runner.emit).should('be.calledWith', 'studio:save') + }) + }) + }) + }) + }) +}) diff --git a/packages/reporter/cypress/e2e/unit/app_state.cy.ts b/packages/reporter/cypress/e2e/unit/app_state.cy.ts new file mode 100644 index 0000000000..1171ecc8a6 --- /dev/null +++ b/packages/reporter/cypress/e2e/unit/app_state.cy.ts @@ -0,0 +1,231 @@ +import appState, { AppState } from '../../../src/lib/app-state' + +describe('app state', () => { + it('exports singleton by default', () => { + expect(appState).to.be.instanceof(AppState) + }) + + context('#startRunning', () => { + it('sets isRunning to true', () => { + const instance = new AppState() + + instance.startRunning() + expect(instance.isRunning).to.be.true + }) + + it('sets isStopped to false', () => { + const instance = new AppState() + + instance.isStopped = true + instance.startRunning() + expect(instance.isStopped).to.be.false + }) + }) + + context('#pause', () => { + it('sets isPaused to true', () => { + const instance = new AppState() + + instance.pause() + expect(instance.isPaused).to.be.true + }) + + it('sets the next command name', () => { + const instance = new AppState() + + instance.pause('next command') + expect(instance.nextCommandName).to.equal('next command') + }) + }) + + context('#resume', () => { + it('sets isPaused to false', () => { + const instance = new AppState() + + instance.resume() + expect(instance.isPaused).to.be.false + }) + + it('unsets the next command name', () => { + const instance = new AppState() + + instance.resume() + expect(instance.nextCommandName).to.be.null + }) + }) + + context('#stop', () => { + it('sets isStopped to true', () => { + const instance = new AppState() + + instance.stop() + expect(instance.isStopped).to.be.true + }) + }) + + context('#end', () => { + it('sets isRunning to false', () => { + const instance = new AppState() + + instance.end() + expect(instance.isRunning).to.be.false + }) + + it('resets autoScrollingEnabled', () => { + const instance = new AppState() + + instance.temporarilySetAutoScrolling(false) + instance.end() + expect(instance.autoScrollingEnabled).to.be.true + }) + }) + + context('#temporarilySetAutoScrolling', () => { + it('sets autoScrollingEnabled to boolean specified', () => { + const instance = new AppState() + + instance.temporarilySetAutoScrolling(false) + expect(instance.autoScrollingEnabled).to.be.false + }) + + it('does nothing if argument is null', () => { + const instance = new AppState() + + instance.temporarilySetAutoScrolling(null) + expect(instance.autoScrollingEnabled).to.be.true + }) + + it('does nothing if argument is undefined', () => { + const instance = new AppState() + + instance.temporarilySetAutoScrolling() + expect(instance.autoScrollingEnabled).to.be.true + }) + }) + + context('#setAutoScrolling', () => { + it('sets autoScrollingEnabled', () => { + const instance = new AppState() + + instance.setAutoScrolling(false) + expect(instance.autoScrollingEnabled).to.be.false + instance.setAutoScrolling(true) + expect(instance.autoScrollingEnabled).to.be.true + }) + + it('sets reset value for autoScrollingEnabled', () => { + const instance = new AppState() + + instance.setAutoScrolling(false) + instance.reset() + expect(instance.autoScrollingEnabled).to.be.false + }) + }) + + context('#toggleAutoScrolling', () => { + it('toggles autoScrollingEnabled', () => { + const instance = new AppState() + + instance.toggleAutoScrolling() + expect(instance.autoScrollingEnabled).to.be.false + instance.toggleAutoScrolling() + expect(instance.autoScrollingEnabled).to.be.true + }) + + it('sets reset value for autoScrollingEnabled', () => { + const instance = new AppState() + + instance.toggleAutoScrolling() + instance.reset() + expect(instance.autoScrollingEnabled).to.be.false + }) + }) + + context('#togglePreferencesMenu', () => { + it('toggles isPreferencesMenuOpen', () => { + const instance = new AppState() + + instance.togglePreferencesMenu() + expect(instance.isPreferencesMenuOpen).to.be.true + instance.togglePreferencesMenu() + expect(instance.isPreferencesMenuOpen).to.be.false + }) + + it('sets reset value for autoScrollingEnabled', () => { + const instance = new AppState() + + instance.togglePreferencesMenu() + instance.reset() + expect(instance.autoScrollingEnabled).to.be.true + }) + }) + + context('#setStudioActive', () => { + it('sets studioActive', () => { + const instance = new AppState() + + instance.setStudioActive(true) + expect(instance.studioActive).to.eq(true) + instance.setStudioActive(false) + expect(instance.studioActive).to.eq(false) + }) + }) + + context('#reset', () => { + it('resets autoScrollingEnabled when it has not been toggled', () => { + const instance = new AppState() + + instance.temporarilySetAutoScrolling(false) + instance.reset() + expect(instance.autoScrollingEnabled).to.be.true + }) + + it('does not reset autoScrollingEnabled when it has been toggled', () => { + const instance = new AppState() + + instance.toggleAutoScrolling() + instance.reset() + expect(instance.autoScrollingEnabled).to.be.false + }) + + it('sets isPaused to false', () => { + const instance = new AppState() + + instance.isPaused = true + instance.reset() + expect(instance.isPaused).to.be.false + }) + + it('sets isRunning to false', () => { + const instance = new AppState() + + instance.isRunning = true + instance.reset() + expect(instance.isRunning).to.be.false + }) + + it('sets nextCommandName to null', () => { + const instance = new AppState() + + instance.nextCommandName = 'next command' + instance.reset() + expect(instance.nextCommandName).to.be.null + }) + + it('sets pinnedSnapshotId to null', () => { + const instance = new AppState() + + instance.pinnedSnapshotId = 'c4' + instance.reset() + expect(instance.pinnedSnapshotId).to.be.null + }) + + it('sets studioActive to false', () => { + const instance = new AppState() + + instance.studioActive = true + instance.reset() + expect(instance.studioActive).to.be.false + }) + }) +}) diff --git a/packages/reporter/cypress/integration/unit/command_model_spec.ts b/packages/reporter/cypress/e2e/unit/command_model.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/command_model_spec.ts rename to packages/reporter/cypress/e2e/unit/command_model.cy.ts diff --git a/packages/reporter/cypress/integration/unit/err_model_spec.ts b/packages/reporter/cypress/e2e/unit/err_model.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/err_model_spec.ts rename to packages/reporter/cypress/e2e/unit/err_model.cy.ts diff --git a/packages/reporter/cypress/e2e/unit/events.cy.ts b/packages/reporter/cypress/e2e/unit/events.cy.ts new file mode 100644 index 0000000000..92080068af --- /dev/null +++ b/packages/reporter/cypress/e2e/unit/events.cy.ts @@ -0,0 +1,401 @@ +import sinon, { SinonSpy, SinonStub } from 'sinon' + +import events from '../../../src/lib/events' +import { AppState } from '../../../src/lib/app-state' +import { RunnablesStore } from '../../../src/runnables/runnables-store' +import { Scroller } from '../../../src/lib/scroller' +import { StatsStore } from '../../../src/header/stats-store' + +interface RunnerStub { + on: SinonSpy + emit: SinonSpy +} + +const runnerStub = (): RunnerStub => { + return { + on: sinon.stub(), + emit: sinon.spy(), + } +} + +type AppStateStub = AppState & { + startRunning: SinonSpy + pause: SinonSpy + reset: SinonSpy + resume: SinonSpy + end: SinonSpy + temporarilySetAutoScrolling: SinonSpy + setStudioActive: SinonSpy + stop: SinonSpy +} + +const appStateStub = () => { + return { + startRunning: sinon.spy(), + pause: sinon.spy(), + reset: sinon.spy(), + resume: sinon.spy(), + end: sinon.spy(), + temporarilySetAutoScrolling: sinon.spy(), + setStudioActive: sinon.spy(), + stop: sinon.spy(), + } as AppStateStub +} + +type RunnablesStoreStub = RunnablesStore & { + addLog: SinonSpy + reset: SinonSpy + runnableStarted: SinonSpy + runnableFinished: SinonSpy + setInitialScrollTop: SinonStub + setRunnables: SinonSpy + testById: SinonStub + updateLog: SinonSpy + removeLog: SinonSpy +} + +const runnablesStoreStub = () => { + return { + addLog: sinon.spy(), + reset: sinon.spy(), + runnableStarted: sinon.spy(), + runnableFinished: sinon.spy(), + setInitialScrollTop: sinon.stub(), + setRunnables: sinon.spy(), + testById: sinon.stub(), + updateLog: sinon.spy(), + removeLog: sinon.spy(), + } as RunnablesStoreStub +} + +type ScrollerStub = Scroller & { + getScrollTop: SinonStub +} + +const scrollerStub = () => { + return { + getScrollTop: sinon.stub(), + } as ScrollerStub +} + +type StatsStoreStub = StatsStore & { + incrementCount: SinonSpy + pause: SinonSpy + reset: SinonSpy + resume: SinonSpy + start: SinonSpy + startRunning: SinonSpy + end: SinonSpy +} + +const statsStoreStub = () => { + return { + incrementCount: sinon.spy(), + pause: sinon.spy(), + reset: sinon.spy(), + resume: sinon.spy(), + start: sinon.spy(), + startRunning: sinon.spy(), + end: sinon.spy(), + } as StatsStoreStub +} + +describe('events', () => { + let appState: AppStateStub + let runnablesStore: RunnablesStoreStub + let scroller: ScrollerStub + let statsStore: StatsStoreStub + let runner: RunnerStub + + beforeEach(() => { + events.__off() + + appState = appStateStub() + runnablesStore = runnablesStoreStub() + scroller = scrollerStub() + statsStore = statsStoreStub() + events.init({ appState, runnablesStore, scroller, statsStore }) + + runner = runnerStub() + events.listen(runner) + }) + + context('from runner', () => { + it('sets runnables on runnables:ready', () => { + runner.on.withArgs('runnables:ready').callArgWith(1, 'root runnable') + expect(runnablesStore.setRunnables).to.have.been.calledWith('root runnable') + }) + + it('adds log on reporter:log:add', () => { + runner.on.withArgs('reporter:log:add').callArgWith(1, 'the log') + expect(runnablesStore.addLog).to.have.been.calledWith('the log') + }) + + it('updates log on reporter:log:state:changed', () => { + runner.on.withArgs('reporter:log:state:changed').callArgWith(1, 'the updated log') + expect(runnablesStore.updateLog).to.have.been.calledWith('the updated log') + }) + + it('deletes log on reporter:log:remove', () => { + runner.on.withArgs('reporter:log:remove').callArgWith(1, 'the deleted log') + expect(runnablesStore.removeLog).to.have.been.calledWith('the deleted log') + }) + + it('resets runnables on reporter:restart:test:run', () => { + runner.on.withArgs('reporter:restart:test:run').callArgWith(1) + expect(runnablesStore.reset).to.have.been.called + }) + + it('resets stats on reporter:restart:test:run', () => { + runner.on.withArgs('reporter:restart:test:run').callArgWith(1) + expect(statsStore.reset).to.have.been.called + }) + + it('resets appState on reporter:restart:test:run', () => { + runner.on.withArgs('reporter:restart:test:run').callArgWith(1) + expect(appState.reset).to.have.been.called + }) + + it('emits reporter:restarted on reporter:restart:test:run', () => { + runner.on.withArgs('reporter:restart:test:run').callArgWith(1) + expect(runner.emit).to.have.been.calledWith('reporter:restarted') + }) + + it('starts running stats on run:start if there are tests', () => { + runnablesStore.hasTests = true + runner.on.withArgs('run:start').callArgWith(1) + expect(appState.startRunning).to.have.been.called + }) + + it('does not start running stats on run:start if there are no tests', () => { + runnablesStore.hasTests = false + runner.on.withArgs('run:start').callArgWith(1) + expect(appState.startRunning).not.to.have.been.called + }) + + it('starts stats on reporter:start', () => { + runnablesStore.hasTests = true + runner.on.withArgs('reporter:start').callArgWith(1, {}) + expect(statsStore.start).to.have.been.calledWith({}) + }) + + it('does not start stats if there are no tests on reporter:start', () => { + runnablesStore.hasTests = false + runner.on.withArgs('reporter:start').callArgWith(1, {}) + expect(statsStore.start).not.to.have.been.called + }) + + it('sets autoScrollingEnabled on the app state on reporter:start', () => { + runner.on.withArgs('reporter:start').callArgWith(1, { autoScrollingEnabled: false }) + expect(appState.temporarilySetAutoScrolling).to.have.been.calledWith(false) + }) + + it('sets studioActive on the app state on reporter:start', () => { + runner.on.withArgs('reporter:start').callArgWith(1, { studioActive: true }) + expect(appState.setStudioActive).to.have.been.calledWith(true) + }) + + it('sets initial scrollTop on the scroller on reporter:start', () => { + runner.on.withArgs('reporter:start').callArgWith(1, { scrollTop: 123 }) + expect(runnablesStore.setInitialScrollTop).to.have.been.calledWith(123) + }) + + it('sends runnable started on test:before:run:async', () => { + runner.on.withArgs('test:before:run:async').callArgWith(1, 'the runnable') + expect(runnablesStore.runnableStarted).to.have.been.calledWith('the runnable') + }) + + it('sends runnable finished on test:after:run', () => { + runner.on.withArgs('test:after:run').callArgWith(1, 'the runnable') + expect(runnablesStore.runnableFinished).to.have.been.calledWith('the runnable') + }) + + it('increments the stats count on test:after:run if final: true', () => { + runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed', final: true }) + expect(statsStore.incrementCount).to.have.been.calledWith('passed') + }) + + it('does not increment the stats count on test:after:run if not final: true', () => { + runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed' }) + expect(statsStore.incrementCount).not.to.have.been.called + }) + + it('does not increment the stats count if studio is active', () => { + appState.studioActive = true + runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed', final: true }) + expect(statsStore.incrementCount).not.to.have.been.calledWith('passed') + }) + + it('pauses the appState with next command name on paused', () => { + runner.on.withArgs('paused').callArgWith(1, 'next command') + expect(appState.pause).to.have.been.calledWith('next command') + }) + + it('pauses the stats on paused', () => { + runner.on.withArgs('paused').callArgWith(1, 'next command') + expect(statsStore.pause).to.have.been.called + }) + + it('ends the appState on run:end', () => { + runner.on.withArgs('run:end').callArgWith(1) + expect(appState.end).to.have.been.called + }) + + it('ends the stats on run:end', () => { + runner.on.withArgs('run:end').callArgWith(1) + expect(statsStore.end).to.have.been.called + }) + + it('calls callback with scrollTop and autoScrollingEnabled on reporter:collect:run:state', () => { + const callback = sinon.spy() + + appState.autoScrollingEnabled = false + scroller.getScrollTop.returns(321) + runner.on.withArgs('reporter:collect:run:state').callArgWith(1, callback) + expect(callback).to.have.been.calledWith({ + autoScrollingEnabled: false, + scrollTop: 321, + }) + }) + + it('nullifies the appState pinned snapshot id on reporter:snapshot:unpinned', () => { + appState.pinnedSnapshotId = 'c1' + runner.on.withArgs('reporter:snapshot:unpinned').callArgWith(1) + expect(appState.pinnedSnapshotId).to.be.null + }) + }) + + context('from local bus', () => { + it('resumes the appState on resume', () => { + events.emit('resume') + expect(appState.resume).to.have.been.called + }) + + it('resumes the stats on resume', () => { + events.emit('resume') + expect(statsStore.resume).to.have.been.called + }) + + it('emits runner:resume on resume', () => { + events.emit('resume') + expect(runner.emit).to.have.been.calledWith('runner:resume') + }) + + it('emits runner:next on next', () => { + events.emit('next') + expect(runner.emit).to.have.been.calledWith('runner:next') + }) + + it('stops the appState on stop', () => { + events.emit('stop') + expect(appState.stop).to.have.been.called + }) + + it('emits runner:stop on stop', () => { + events.emit('stop') + expect(runner.emit).to.have.been.calledWith('runner:stop') + }) + + it('emits runner:restart on restart', () => { + events.emit('restart') + expect(runner.emit).to.have.been.calledWith('runner:restart') + }) + + it('emits runner:console:log on show:command', () => { + events.emit('show:command', 'command id') + expect(runner.emit).to.have.been.calledWith('runner:console:log', 'command id') + }) + + it('emits runner:console:error with test id on show:error', () => { + const test = { err: { isCommandErr: false } } + + runnablesStore.testById.returns(test) + events.emit('show:error', test) + expect(runner.emit).to.have.been.calledWith('runner:console:error', { + err: test.err, + commandId: undefined, + }) + }) + + it('emits runner:console:error with test id and command id on show:error when it is a command error and there is a matching command', () => { + const test = { err: { isCommandErr: true }, commandMatchingErr: () => { + return { id: 'matching command id' } + } } + + runnablesStore.testById.returns(test) + events.emit('show:error', test) + expect(runner.emit).to.have.been.calledWith('runner:console:error', { + err: test.err, + commandId: 'matching command id', + }) + }) + + it('emits runner:console:error with test id on show:error when it is a command error but there not a matching command', () => { + const test = { err: { isCommandErr: true }, commandMatchingErr: () => { + return null + } } + + runnablesStore.testById.returns(test) + events.emit('show:error', test) + expect(runner.emit).to.have.been.calledWith('runner:console:error', { + err: test.err, + commandId: undefined, + }) + }) + + it('emits runner:show:snapshot on show:snapshot', () => { + events.emit('show:snapshot', 'command id') + expect(runner.emit).to.have.been.calledWith('runner:show:snapshot', 'command id') + }) + + it('emits runner:hide:snapshot on hide:snapshot', () => { + events.emit('hide:snapshot', 'command id') + expect(runner.emit).to.have.been.calledWith('runner:hide:snapshot', 'command id') + }) + + it('emits runner:pin:snapshot on pin:snapshot', () => { + events.emit('pin:snapshot', 'command id') + expect(runner.emit).to.have.been.calledWith('runner:pin:snapshot', 'command id') + }) + + it('emits runner:unpin:snapshot on unpin:snapshot', () => { + events.emit('unpin:snapshot', 'command id') + expect(runner.emit).to.have.been.calledWith('runner:unpin:snapshot', 'command id') + }) + + it('emits save:state on save:state', () => { + appState.autoScrollingEnabled = false + appState.isSpecsListOpen = true + events.emit('save:state') + expect(runner.emit).to.have.been.calledWith('save:state', { + autoScrollingEnabled: false, + isSpecsListOpen: true, + }) + }) + + it('emits studio:init:test with test id on studio:init:test', () => { + events.emit('studio:init:test', 'test id') + expect(runner.emit).to.have.been.calledWith('studio:init:test', 'test id') + }) + + it('emits studio:init:suite with test id on studio:init:suite', () => { + events.emit('studio:init:suite', 'suite id') + expect(runner.emit).to.have.been.calledWith('studio:init:suite', 'suite id') + }) + + it('emits studio:remove:command with command id on studio:remove:command', () => { + events.emit('studio:remove:command', 'command id') + expect(runner.emit).to.have.been.calledWith('studio:remove:command', 'command id') + }) + + it('emits studio:cancel on studio:cancel', () => { + events.emit('studio:cancel') + expect(runner.emit).to.have.been.calledWith('studio:cancel') + }) + + it('emits studio:save on studio:save', () => { + events.emit('studio:save') + expect(runner.emit).to.have.been.calledWith('studio:save') + }) + }) +}) diff --git a/packages/reporter/cypress/integration/unit/hook_model_spec.ts b/packages/reporter/cypress/e2e/unit/hook_model.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/hook_model_spec.ts rename to packages/reporter/cypress/e2e/unit/hook_model.cy.ts diff --git a/packages/reporter/cypress/integration/unit/runnables_store_spec.ts b/packages/reporter/cypress/e2e/unit/runnables_store.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/runnables_store_spec.ts rename to packages/reporter/cypress/e2e/unit/runnables_store.cy.ts diff --git a/packages/reporter/cypress/integration/unit/scroller_spec.ts b/packages/reporter/cypress/e2e/unit/scroller.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/scroller_spec.ts rename to packages/reporter/cypress/e2e/unit/scroller.cy.ts diff --git a/packages/reporter/cypress/integration/unit/stats_store_spec.ts b/packages/reporter/cypress/e2e/unit/stats_store.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/stats_store_spec.ts rename to packages/reporter/cypress/e2e/unit/stats_store.cy.ts diff --git a/packages/reporter/cypress/integration/unit/suite_model_spec.ts b/packages/reporter/cypress/e2e/unit/suite_model.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/suite_model_spec.ts rename to packages/reporter/cypress/e2e/unit/suite_model.cy.ts diff --git a/packages/reporter/cypress/integration/unit/test_model_spec.ts b/packages/reporter/cypress/e2e/unit/test_model.cy.ts similarity index 100% rename from packages/reporter/cypress/integration/unit/test_model_spec.ts rename to packages/reporter/cypress/e2e/unit/test_model.cy.ts diff --git a/packages/reporter/cypress/e2e/unit/util.cy.ts b/packages/reporter/cypress/e2e/unit/util.cy.ts new file mode 100644 index 0000000000..de73c3be7e --- /dev/null +++ b/packages/reporter/cypress/e2e/unit/util.cy.ts @@ -0,0 +1,83 @@ +import { formatDuration, getFilenameParts } from '../../../src/lib/util' + +const compare = (filename, array) => { + expect(getFilenameParts(filename)).to.deep.equal(array) +} + +describe('utils', () => { + context('formatDuration', () => { + it('formats no time', () => { + expect(formatDuration(0)).to.equal('--') + }) + + it('formats time of <1s', () => { + expect(formatDuration(1)).to.equal('1ms') + expect(formatDuration(999)).to.equal('999ms') + }) + + it('formats time of >=1s', () => { + expect(formatDuration(1000)).to.equal('00:01') + expect(formatDuration(1400)).to.equal('00:01') + expect(formatDuration(35620)).to.equal('00:36') + expect(formatDuration(59200)).to.equal('00:59') + }) + + it('formats time of >=1m', () => { + expect(formatDuration(60000)).to.equal('01:00') + expect(formatDuration(600000)).to.equal('10:00') + expect(formatDuration(3599000)).to.equal('59:59') + }) + + it('formats time of >=1h', () => { + expect(formatDuration(3600000)).to.equal('1:00:00') + expect(formatDuration(4200000)).to.equal('1:10:00') + expect(formatDuration(7199000)).to.equal('1:59:59') + }) + + it('displays larger times in hours', () => { + expect(formatDuration(360000000)).to.equal('100:00:00') + }) + }) + + context('getFilenameParts', () => { + it('splits basic filenames', () => { + compare('something.foo.ts', ['something.foo', '.ts']) + compare('first-user.js', ['first-user', '.js']) + compare('model.coffee', ['model', '.coffee']) + }) + + it('handles .spec, .test, and .cy', () => { + compare('basic.spec.ts', ['basic', '.spec.ts']) + compare('spies_stubs_clocks.spec.js', ['spies_stubs_clocks', '.spec.js']) + compare('newIssuanceWorkflow.test.js', ['newIssuanceWorkflow', '.test.js']) + compare('Button.cy.js', ['Button', '.cy.js']) + }) + + it('does not consider "_spec" to be part of the extension', () => { + // might want to change this functionality later, but for now this is working as intended + compare('warning_spec.js', ['warning_spec', '.js']) + }) + + it('behaves as expected if "spec" is in the filename', () => { + compare('spec.ts', ['spec', '.ts']) + compare('spec_spec.ts', ['spec_spec', '.ts']) + }) + + it('handles no file extension', () => { + compare('no-extension', ['no-extension', '']) + }) + + it('strips directory path', () => { + compare('unit/spec_split_spec.ts', ['spec_split_spec', '.ts']) + compare('dir/unit/spec_split_spec.ts', ['spec_split_spec', '.ts']) + }) + + it('displays filename with special characters', () => { + compare('cypress/integration/meta_&%.cy.ts', ['meta_&%', '.cy.ts']) + }) + + it('handles an unexpected number of extensions', () => { + compare('reporter.hooks.spec.js', ['reporter.hooks', '.spec.js']) + }) + }) +}) diff --git a/packages/reporter/cypress/fixtures/runnables_agents.json b/packages/reporter/cypress/fixtures/runnables_agents.json index ea80a1dcc4..52c2ea93ab 100644 --- a/packages/reporter/cypress/fixtures/runnables_agents.json +++ b/packages/reporter/cypress/fixtures/runnables_agents.json @@ -12,7 +12,7 @@ { "id": 1, "functionName": "get", - "type": "spy", + "name": "spy", "alias": "getAlias", "instrument": "agent", "callCount": 1 @@ -20,7 +20,7 @@ { "id": 2, "functionName": "fetch", - "type": "stub", + "name": "stub-1", "alias": ["fetchAlias", "gonnaHappenAlias"], "instrument": "agent", "callCount": 3 @@ -28,7 +28,7 @@ { "id": 3, "functionName": "go", - "type": "stub", + "name": "stub-2", "instrument": "agent", "callCount": 0 } diff --git a/packages/reporter/cypress/integration/agents_spec.ts b/packages/reporter/cypress/integration/agents_spec.ts deleted file mode 100644 index a057115565..0000000000 --- a/packages/reporter/cypress/integration/agents_spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from './../../src/runnables/runnables-store' - -describe('agents', () => { - let runner: EventEmitter - let runnables: RootRunnable - let start: Function - - beforeEach(() => { - cy.fixture('runnables_agents').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - }) - }) - - start = () => { - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - - cy.contains('http://localhost:3000') // ensure test content has loaded - } - }) - - it('does not display agents if there are no agents', () => { - // @ts-ignore - runnables.tests[0].agents = [] - start() - - cy.contains('Spies / Stubs').should('not.be.visible') - }) - - describe('when there are agents', () => { - it('displays collapsible header with number of agents', () => { - start() - cy.contains('Spies / Stubs (3)').should('be.visible') - }) - - it('collapses agents by default', () => { - start() - cy.get('.runnable-agents-region .instrument-content').should('not.be.visible') - }) - - it('shows agents after expanding', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.runnable-agents-region .instrument-content').should('be.visible') - cy.percySnapshot() - }) - - it('displays each of the agents', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').should('have.length', 3) - }) - - it('does not include no-calls class if there is a non-zero callCount', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').first().should('not.have.class', 'no-calls') - }) - - it('includes no-calls class if zero callCount', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').eq(2).should('have.class', 'no-calls') - }) - - it('displays the type', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').eq(0).find('td').first().should('have.text', 'spy') - cy.get('.agent-item').eq(1).find('td').first().should('have.text', 'stub') - cy.get('.agent-item').eq(2).find('td').first().should('have.text', 'stub') - }) - - it('displays the function name', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').eq(0).find('td').eq(1).should('have.text', 'get') - cy.get('.agent-item').eq(1).find('td').eq(1).should('have.text', 'fetch') - cy.get('.agent-item').eq(2).find('td').eq(1).should('have.text', 'go') - }) - - it('displays alias when singular or multiple, but not when absent', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').eq(0).find('td').eq(2).should('have.text', 'getAlias') - cy.get('.agent-item').eq(1).find('td').eq(2).should('have.text', 'fetchAlias, gonnaHappenAlias') - cy.get('.agent-item').eq(2).find('td').eq(2).should('have.text', '') - }) - - it('displays the callCount if non-zero or "-" if zero', () => { - start() - cy.contains('Spies / Stubs (3)').click() - - cy.get('.agent-item').eq(0).find('td').eq(3).should('have.text', '1') - cy.get('.agent-item').eq(1).find('td').eq(3).should('have.text', '3') - cy.get('.agent-item').eq(2).find('td').eq(3).should('have.text', '-') - }) - }) -}) diff --git a/packages/reporter/cypress/integration/aliases_spec.ts b/packages/reporter/cypress/integration/aliases_spec.ts deleted file mode 100644 index 67566c599a..0000000000 --- a/packages/reporter/cypress/integration/aliases_spec.ts +++ /dev/null @@ -1,644 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from './../../src/runnables/runnables-store' -import { addCommand } from '../support/utils' - -describe('aliases', () => { - let runner: EventEmitter - let runnables: RootRunnable - - beforeEach(() => { - cy.fixture('runnables_aliases').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - }) - - context('interceptions + status', () => { - it('shows only status if no alias or dupe', () => { - addCommand(runner, { - aliasType: 'route', - renderProps: { - wentToOrigin: true, - status: 'some status', - interceptions: [{ - type: 'spy', - command: 'intercept', - }], - }, - }) - - cy.contains('.command-number', '1').parent().find('.command-interceptions') - .should('have.text', 'some status no alias') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with no alias') - .percySnapshot() - }) - - it('shows status and count if dupe', () => { - addCommand(runner, { - aliasType: 'route', - renderProps: { - wentToOrigin: true, - status: 'some status', - interceptions: [{ - type: 'spy', - command: 'intercept', - }, { - type: 'spy', - command: 'route', - }], - }, - }) - - cy.contains('.command-number', '1').parent().find('.command-interceptions') - .should('have.text', 'some status no alias') - .parent().find('.command-interceptions-count') - .should('have.text', '2') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with no aliascy.route() spy with no alias') - .percySnapshot() - }) - - it('shows status and alias and count if dupe', () => { - addCommand(runner, { - aliasType: 'route', - alias: 'myAlias', - renderProps: { - wentToOrigin: true, - status: 'some status', - interceptions: [{ - type: 'spy', - command: 'intercept', - alias: 'firstAlias', - }, { - type: 'spy', - command: 'intercept', - alias: 'myAlias', - }], - }, - }) - - cy.contains('.command-number', '1').parent().find('.command-interceptions') - .should('have.text', 'some status myAlias') - .parent().find('.command-interceptions-count') - .should('have.text', '2') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with alias @firstAliascy.intercept() spy with alias @myAlias') - .percySnapshot() - }) - - it('shows status and alias', () => { - addCommand(runner, { - aliasType: 'route', - alias: 'myAlias', - renderProps: { - wentToOrigin: true, - status: 'some status', - interceptions: [{ - type: 'spy', - command: 'intercept', - alias: 'myAlias', - }], - }, - }) - - cy.contains('.command-number', '1').parent().find('.command-interceptions') - .should('have.text', 'some status myAlias') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', 'This request matched:cy.intercept() spy with alias @myAlias') - .percySnapshot() - }) - }) - - context('route aliases', () => { - describe('without duplicates', () => { - beforeEach(() => { - addCommand(runner, { - alias: 'getUsers', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - renderProps: { - message: 'GET --- /users', - indicator: 'passed', - wentToOrigin: false, - interceptions: [{ - type: 'stub', - command: 'route', - alias: 'getUsers', - }], - }, - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getUsers, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 1, - name: 'getUsers', - ordinal: '1st', - }], - }) - }) - - it('has correct alias class', () => { - cy.contains('.command-number', '1') - .parent() - .find('.command-alias') - .should('have.class', 'route') - }) - - it('render without a count', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@getUsers') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'getUsers\'') - }) - - cy.percySnapshot() - }) - }) - - describe('with consecutive duplicates', () => { - beforeEach(() => { - addCommand(runner, { - alias: 'getPosts', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - // @ts-ignore - renderProps: { message: 'GET --- /posts', indicator: 'passed', interceptions: [{ alias: 'getPosts' }] }, - }) - - addCommand(runner, { - alias: 'getPosts', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - // @ts-ignore - renderProps: { message: 'GET --- /posts', indicator: 'passed', interceptions: [{ alias: 'getPosts' }] }, - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getPosts, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 1, - name: 'getPosts', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getPosts, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 2, - name: 'getPosts', - ordinal: '2nd', - }], - }) - }) - - it('renders all aliases ', () => { - cy.get('.command-alias').should('have.length', 2) - cy.percySnapshot() - }) - - it('render with counts in non-event commands', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.contains('.command-alias-count', '1') - - cy.contains('.command-alias', '@getPosts') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found 1st alias for: \'getPosts\'') - }) - - cy.contains('.command-number', '2') - .parent() - .within(() => { - cy.contains('.command-alias-count', '2') - - cy.contains('.command-alias', '@getPosts') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found 2nd alias for: \'getPosts\'') - }) - }) - - it('render with counts in event commands when collapsed', () => { - cy.get('.command-wrapper') - .first() - .within(() => { - cy.contains('.num-children', '2') - - cy.contains('.command-interceptions', 'getPosts') - }) - }) - - it('render without counts in event commands when expanded', () => { - cy.get('.command-expander') - .first() - .click() - - cy.get('.command-wrapper') - .first() - .within(() => { - cy.get('.num-children').should('not.exist') - - cy.contains('.command-interceptions', 'getPosts') - }) - }) - }) - - describe('with non-consecutive duplicates', () => { - beforeEach(() => { - addCommand(runner, { - alias: 'getPosts', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - renderProps: { - message: 'GET --- /users', - indicator: 'passed', - wentToOrigin: false, - interceptions: [{ - type: 'stub', - command: 'route', - alias: 'getUsers', - }], - }, - }) - - addCommand(runner, { - alias: 'getUsers', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - renderProps: { - message: 'GET --- /users', - indicator: 'passed', - wentToOrigin: false, - interceptions: [{ - type: 'stub', - command: 'route', - alias: 'getUsers', - }], - }, - }) - - addCommand(runner, { - alias: 'getPosts', - aliasType: 'route', - displayName: 'xhr', - event: true, - name: 'xhr', - renderProps: { - message: 'GET --- /posts', - indicator: 'passed', - wentToOrigin: false, - interceptions: [{ - type: 'stub', - command: 'route', - alias: 'getPosts', - }], - }, - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getPosts, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 1, - name: 'getPosts', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getUsers, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 1, - name: 'getUsers', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'route', - message: '@getPosts, function(){}', - name: 'wait', - referencesAlias: [{ - cardinal: 2, - name: 'getPosts', - ordinal: '2nd', - }], - }) - }) - - it('render with counts', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.contains('.command-alias-count', '1') - - cy.contains('.command-alias', '@getPosts') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found 1st alias for: \'getPosts\'') - }) - - cy.contains('.command-number', '3') - .parent() - .within(() => { - cy.contains('.command-alias-count', '2') - - cy.contains('.command-alias', '@getPosts') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found 2nd alias for: \'getPosts\'') - }) - - cy.percySnapshot() - }) - }) - }) - - context('element aliases', () => { - describe('without duplicates', () => { - beforeEach(() => { - addCommand(runner, { - state: 'passed', - name: 'get', - message: 'body', - alias: 'barAlias', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 1, - name: 'barAlias', - ordinal: '1st', - }], - }) - }) - - it('has correct alias class', () => { - cy.contains('.command-number', '1') - .parent() - .find('.command-alias') - .should('have.class', 'dom') - }) - - it('render without a count', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@barAlias') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'barAlias\'') - }) - }) - }) - - describe('with consecutive duplicates', () => { - beforeEach(() => { - addCommand(runner, { - state: 'passed', - name: 'get', - message: '[attr=\'dropdown\']', - alias: 'dropdown', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - state: 'passed', - name: 'get', - message: 'select', - alias: 'dropdown', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 1, - name: 'dropdown', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 2, - name: 'dropdown', - ordinal: '2nd', - }], - }) - }) - - it('render without a count in non-event commands', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@dropdown') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'dropdown\'') - }) - - cy.contains('.command-number', '2') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@dropdown') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'dropdown\'') - }) - }) - - it('render without counts in event commands when collapsed', () => { - cy.get('.command-wrapper') - .first() - .within(() => { - cy.get('.num-children').should('not.exist') - - cy.contains('.command-alias', 'dropdown') - }) - }) - }) - - describe('with non-consecutive duplicates', () => { - beforeEach(() => { - addCommand(runner, { - state: 'passed', - name: 'get', - message: '[attr=\'dropdown\']', - alias: 'dropdown', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - state: 'passed', - name: 'get', - message: '[attr=\'modal\']', - alias: 'modal', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - state: 'passed', - name: 'get', - message: '[attr=\'dropdown\']', - alias: 'dropdown', - aliasType: 'dom', - event: true, - renderProps: { message: '', indicator: 'passed' }, - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 1, - name: 'dropdown', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 1, - name: 'modal', - ordinal: '1st', - }], - }) - - addCommand(runner, { - aliasType: 'dom', - message: '', - name: 'get', - referencesAlias: [{ - cardinal: 2, - name: 'dropdown', - ordinal: '2nd', - }], - }) - }) - - it('renders all aliases ', () => { - cy.get('.command-alias').should('have.length', 6) - }) - - it('render without counts', () => { - cy.contains('.command-number', '1') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@dropdown') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'dropdown\'') - }) - - cy.contains('.command-number', '3') - .parent() - .within(() => { - cy.get('.command-alias-count').should('not.exist') - - cy.contains('.command-alias', '@dropdown') - .trigger('mouseover') - }) - - cy.get('.cy-tooltip span').should(($tooltip) => { - expect($tooltip).to.contain('Found an alias for: \'dropdown\'') - }) - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/commands_spec.ts b/packages/reporter/cypress/integration/commands_spec.ts deleted file mode 100644 index b0cf07aad3..0000000000 --- a/packages/reporter/cypress/integration/commands_spec.ts +++ /dev/null @@ -1,681 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from '../../src/runnables/runnables-store' -import { addCommand } from '../support/utils' - -describe('commands', () => { - let runner: EventEmitter - let runnables: RootRunnable - const inProgressStartedAt = (new Date(2000, 0, 1)).toISOString() - - beforeEach(() => { - cy.fixture('runnables_commands').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - addCommand(runner, { - id: 9, - name: 'get', - message: '#in-progress', - state: 'pending', - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - }) - - cy.contains('http://localhost:3000') // ensure test content has loaded - }) - - it('displays all the commands', () => { - addCommand(runner, { - id: 102, - name: 'get', - message: '#element', - state: 'passed', - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 124, - name: 'within', - state: 'passed', - type: 'child', - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 125, - name: 'get', - message: '#my_element', - state: 'passed', - timeout: 4000, - group: 124, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 129, - name: 'within', - state: 'passed', - type: 'child', - group: 124, - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 130, - name: 'get', - message: '#my_element that _has_ a really long message to show **wrapping** works as expected', - state: 'passed', - timeout: 4000, - groupLevel: 1, - group: 129, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 1229, - name: 'within', - state: 'passed', - type: 'child', - group: 130, - groupLevel: 1, - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 1311, - name: 'get', - message: '#my_element_nested', - state: 'passed', - timeout: 4000, - groupLevel: 2, - group: 1229, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 1291, - name: 'assert', - type: 'child', - message: 'has class named .omg', - state: 'passed', - timeout: 4000, - group: 1229, - groupLevel: 2, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 1291, - name: 'log', - message: 'do something else', - state: 'passed', - timeout: 4000, - group: 130, - groupLevel: 1, - wallClockStartedAt: inProgressStartedAt, - }) - - addCommand(runner, { - id: 135, - name: 'and', - type: 'child', - message: 'has class named .lets-roll', - state: 'passed', - timeout: 4000, - group: 124, - wallClockStartedAt: inProgressStartedAt, - }) - - const indicators = ['successful', 'pending', 'aborted', 'bad'] - - indicators.forEach((indicator, index) => { - addCommand(runner, { - id: 1600 + index, - name: 'xhr', - event: true, - state: 'passed', - timeout: 4000, - renderProps: { - indicator, - message: `${indicator} indicator`, - }, - wallClockStartedAt: inProgressStartedAt, - }) - }) - - const assertStates = ['passed', 'pending', 'failed'] - - assertStates.forEach((state, index) => { - addCommand(runner, { - id: 1700 + index, - name: 'assert', - type: 'child', - message: 'expected **element** to have length of **16** but got **12** instead', - state, - timeout: 4000, - wallClockStartedAt: inProgressStartedAt, - }) - }) - - cy.get('.command').should('have.length', 27) - - cy.percySnapshot() - }) - - it('includes the type class', () => { - cy.contains('#exists').closest('.command') - .should('have.class', 'command-type-parent') - - cy.contains('#doesnt-exist').closest('.command') - .should('have.class', 'command-type-child') - }) - - it('includes the name class', () => { - cy.contains('#exists').closest('.command') - .should('have.class', 'command-name-get') - }) - - it('includes the state class', () => { - addCommand(runner, { - name: 'log', - message: 'command-warning-state', - state: 'warning', - }) - - cy.contains('#exists').closest('.command') - .should('have.class', 'command-state-passed') - - cy.contains('#doesnt-exist').closest('.command') - .should('have.class', 'command-state-failed') - - cy.contains('#in-progress').closest('.command') - .should('have.class', 'command-state-pending') - - cy.contains('command-warning-state').closest('.command') - .should('have.class', 'command-state-warning') - }) - - it('displays the number', () => { - cy.contains('http://localhost:3000').closest('.command-message').siblings('.command-number') - .should('have.text', '1') - - cy.contains('#exists').closest('.command-message').siblings('.command-number') - .should('have.text', '2') - - cy.contains('#doesnt-exist').closest('.command-message').siblings('.command-number') - .should('have.text', '3') - - cy.contains('.some-els').closest('.command-message').siblings('.command-number') - .should('have.text', '4') - }) - - it('events have is-event class, no number, and type in parentheses', () => { - cy.contains('GET ---').closest('.command') - .should('have.class', 'command-is-event') - - cy.contains('GET ---').closest('.command-message').siblings('.command-number') - .should('have.text', '') - - cy.contains('GET ---').closest('.command-message').siblings('.command-method') - .should('have.text', '(xhr stub)') - }) - - it('includes the scaled class when the message is over 100 chars', () => { - cy.contains('Lorem ipsum').closest('.command') - .should('have.class', 'command-scaled') - }) - - it('does not render with the scaled class when the message is less than 100 chars', () => { - cy.contains('#exists').closest('.command') - .should('not.have.class', 'command-scaled') - }) - - it('renders markdown in message', () => { - cy.contains('Lorem ipsum').closest('.command').find('.command-message').within(() => { - cy.get('strong').should('have.text', 'dolor') - cy.get('em').should('have.text', 'sit') - }) - }) - - it('shows indicator when specified', () => { - const indicators = ['successful', 'pending', 'aborted', 'bad'] - - indicators.forEach((indicator) => { - addCommand(runner, { - name: 'xhr', - event: true, - renderProps: { - indicator, - message: `${indicator} indicator`, - }, - }) - }) - - indicators.forEach((indicator) => { - cy.contains(`${indicator} indicator`).closest('.command').find('.command-message .fa-circle') - .should('be.visible') - }) - - cy.percySnapshot() - }) - - it('assert commands for each state', () => { - const assertStates = ['passed', 'pending', 'failed'] - - assertStates.forEach((state) => { - addCommand(runner, { - name: 'assert', - type: 'child', - message: `expected **element** to have **state of ${state}**`, - state, - }) - }) - - cy.get('.command').should('have.length', 13) - - cy.percySnapshot() - }) - - describe('progress bar', () => { - const getProgress = () => { - return cy.contains('#in-progress') - .closest('.command') - .find('.command-progress span') - } - - it('calculates correct scale factor', () => { - // take the wallClockStartedAt of this command and add 2500 milliseconds to it - // in order to simulate the command having run for 2.5 seconds of the total 4000 timeout - const date = new Date(inProgressStartedAt).setMilliseconds(2500) - - cy.clock(date, ['Date']) - // close and open tests so it freshly mounts - cy.contains('test 1').click().click() - getProgress().should(($span) => { - expect($span.attr('style')).to.contain('animation-duration: 1500ms') - expect($span.attr('style')).to.contain('transform: scaleX(0.375)') - - // ensures that actual scale factor hits 0 within default timeout - // this matrix is equivalent to scaleX(0) - expect($span).to.have.css('transform', 'matrix(0, 0, 0, 1, 0, 0)') - }) - }) - - it('recalculates correct scale factor after being closed', () => { - // take the wallClockStartedAt of this command and add 1000 milliseconds to it - // in order to simulate the command having run for 1 second of the total 4000 timeout - const date = new Date(inProgressStartedAt).setMilliseconds(1000) - - cy.clock(date, ['Date']) - // close and open tests so it freshly mounts - cy.contains('test').click().click() - getProgress().should(($span) => { - expect($span.attr('style')).to.contain('animation-duration: 3000ms') - expect($span.attr('style')).to.contain('transform: scaleX(0.75)') - }) - - // set the clock ahead as if time has passed - cy.tick(2000) - - cy.contains('test 1').click().click() - getProgress().should(($span) => { - expect($span.attr('style')).to.contain('animation-duration: 1000ms') - expect($span.attr('style')).to.contain('transform: scaleX(0.25)') - }) - }) - }) - - context('invisible indicator', () => { - it('does not display invisible icon when visible', () => { - cy.contains('#exists').closest('.command').find('.command-invisible') - .should('not.be.visible') - }) - - it('displays invisible icon when not visible', () => { - cy.contains('#doesnt-exist').closest('.command').find('.command-invisible') - .should('be.visible') - }) - - it('displays a tooltip when hovering', () => { - cy.contains('#doesnt-exist').closest('.command').find('.command-invisible').trigger('mouseover') - cy.get('.cy-tooltip') - .should('be.visible') - .should('have.text', 'This element is not visible.') - }) - - it('displays different text when multiple elements', () => { - cy.contains('.invisible').closest('.command').find('.command-invisible').trigger('mouseover') - cy.get('.cy-tooltip') - .should('be.visible') - .should('have.text', 'One or more matched elements are not visible.') - }) - }) - - context('elements indicator', () => { - it('shows number of elements when 0 or greater than 1', () => { - cy.contains('#doesnt-exist').closest('.command').find('.num-elements') - .should('be.visible').and('have.text', '0') - - cy.contains('.some-els').closest('.command').find('.num-elements') - .should('be.visible').and('have.text', '4') - }) - - it('does not show number of elements when 0', () => { - cy.contains('#exists').closest('.command').find('.num-elements') - .should('not.be.visible') - }) - - it('renders a tooltip when hovering', () => { - cy.contains('.some-els').closest('.command').find('.num-elements').trigger('mouseover') - cy.get('.cy-tooltip').should('be.visible').should('have.text', '4 matched elements') - }) - }) - - context('event duplicates', () => { - it('collapses consecutive duplicate events into group', () => { - cy.get('.command-name-xhr').should('have.length', 3) - }) - - it('displays number of duplicates', () => { - cy.contains('GET --- /dup').closest('.command').find('.num-children') - .should('have.text', '4') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', 'This event occurred 4 times') - }) - - it('expands all events after clicking arrow', () => { - cy.contains('GET --- /dup').closest('.command').find('.command-child-container').should('not.exist') - cy.contains('GET --- /dup').closest('.command') - .find('.command-expander').click() - - cy.get('.command-name-xhr').should('have.length', 6) - cy.contains('GET --- /dup').closest('.command').find('.command-child-container') - .should('be.visible') - .find('.command').should('have.length', 3) - }) - }) - - context('clicking', () => { - it('pins the command', () => { - cy.contains('#exists').click() - .closest('.command') - .should('have.class', 'command-is-pinned') - }) - - it('shows a tooltip', () => { - cy.contains('#exists').click() - cy.get('.cy-tooltip').should('have.text', 'Printed output to your console') - }) - - it('tooltip disappears after 1500ms', () => { - cy.clock() - cy.contains('#exists').click() - cy.tick(1500) - cy.get('.cy-tooltip').should('not.exist') - }) - - it('emits runner:console:log', () => { - cy.spy(runner, 'emit') - cy.contains('#exists').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:console:log', 2) - }) - - it('shows the snapshot', () => { - cy.spy(runner, 'emit') - cy.contains('#exists').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:show:snapshot', 2) - }) - - it('unpins after clicking again, does not emit runner:console:log again', () => { - cy.spy(runner, 'emit') - cy.contains('#exists').click() - cy.contains('#exists').click() - // @ts-ignore - cy.wrap(runner.emit.withArgs('runner:console:log')).should('be.calledOnce') - }) - - it('unpins after clicking another command, pins that one', () => { - cy.spy(runner, 'emit') - cy.contains('#exists').click() - cy.contains('#doesnt-exist').click() - cy.contains('#exists').closest('.command') - .should('not.have.class', 'command-is-pinned') - - cy.contains('#doesnt-exist').closest('.command') - .should('have.class', 'command-is-pinned') - }) - }) - - context('mousing over', () => { - beforeEach(() => { - cy.spy(runner, 'emit') - cy.clock() - cy.get('.command-wrapper').first().trigger('mouseover') - - // react uses mouseover for mouseenter events, - // and uses e.fromElement to decide to send it - cy.get('.command-method').first().trigger('mouseover', { - fromElement: cy.$$('.command-wrapper-text:first')[0], - }) - }) - - it('shows snapshot after 50ms passes', () => { - cy.wrap(runner.emit).should('not.be.calledWith', 'runner:show:snapshot') - cy.tick(50) - cy.wrap(runner.emit).should('be.calledWith', 'runner:show:snapshot', 1) - cy.wrap(runner.emit).should('be.calledOnce') - }) - - describe('then mousing out', () => { - beforeEach(() => { - cy.tick(50) - cy.get('.command').first().trigger('mouseout') - }) - - it('hides the snapshot after 50ms pass without another mouse over', () => { - cy.tick(50) - cy.wrap(runner.emit).should('be.calledWith', 'runner:hide:snapshot', 1) - }) - - it('does not hide the snapshot if there is another mouseover before 50ms passes', () => { - cy.wrap(runner.emit).should('not.be.calledWith', 'runner:hide:snapshot') - }) - }) - }) - - context('command group', () => { - let groupId - - beforeEach(() => { - groupId = addCommand(runner, { - name: 'group', - message: 'example group command', - type: 'parent', - }) - - addCommand(runner, { - name: 'get', - message: '#my_nested_element', - group: groupId, - }) - }) - - it('group is open by default when all nested command have passed', () => { - addCommand(runner, { - name: 'log', - message: 'chained log example', - }) - - cy.contains('chained log example') // ensure test content has loaded - - cy.get('.command-name-group') - .should('have.class', 'command-is-open') - .find('.command-expander') - .should('be.visible') - .closest('.command-name-group') - .click() - - cy.get('.command-name-group') - .should('not.have.class', 'command-is-open') - - cy.get('.command-name-group') - .find('.num-children') - .should('have.text', '1') - .trigger('mouseover') - .get('.cy-tooltip').should('have.text', '1 log currently hidden') - .percySnapshot() - }) - - it('group is open by default when last nested command failed', () => { - addCommand(runner, { - name: 'log', - message: 'chained log example', - state: 'failed', - group: groupId, - }) - - cy.contains('chained log example') // ensure test content has loaded - - cy.get('.command-name-group') - .should('have.class', 'command-is-open') - .find('.command-expander') - .should('be.visible') - .closest('.command-name-group') - .click() - - cy.get('.command-name-group') - .find('.num-children') - .should('not.exist') - .percySnapshot() - }) - - it('clicking opens and closes the group', () => { - cy.get('.command-name-group') - .find('.num-children') - .should('not.exist') - - cy.get('.command-name-group') - .should('have.class', 'command-is-open') - .find('.command-expander') - .should('be.visible') - .closest('.command-name-group') - .click() - - cy.get('.command-name-group') - .find('.num-children') - .should('be.visible') - .should('have.text', '1') - - cy.get('.command-name-group') - .should('not.have.class', 'command-is-open') - }) - - it('displays with nested logs', () => { - const nestedGroupId = addCommand(runner, { - name: 'group-2', - state: 'passed', - type: 'child', - group: groupId, - }) - - addCommand(runner, { - name: 'get', - message: '#my_element_nested', - state: 'passed', - group: nestedGroupId, - }) - - addCommand(runner, { - name: 'assert', - type: 'child', - message: 'has class named .omg', - group: nestedGroupId, - }) - - addCommand(runner, { - name: 'log', - message: 'chained log example', - state: 'passed', - group: groupId, - }) - - cy.get('.command-name-group') - .should('have.class', 'command-is-open') - - cy.get('.command-name-group-2') - .should('have.class', 'command-is-open') - .click() - - cy.percySnapshot() - }) - }) - - context('studio commands', () => { - beforeEach(() => { - addCommand(runner, { - id: 10, - number: 7, - name: 'get', - message: '#studio-command-parent', - state: 'success', - isStudio: true, - type: 'parent', - }) - - addCommand(runner, { - id: 11, - name: 'click', - message: '#studio-command-child', - state: 'success', - isStudio: true, - type: 'child', - }) - }) - - it('studio commands have command-is-studio class', () => { - cy.contains('#studio-command-parent').closest('.command') - .should('have.class', 'command-is-studio') - - cy.contains('#studio-command-child').closest('.command') - .should('have.class', 'command-is-studio') - }) - - it('only parent studio commands display remove button', () => { - cy.contains('#studio-command-parent').closest('.command') - .find('.studio-command-remove').should('be.visible') - - cy.contains('#studio-command-child').closest('.command') - .find('.studio-command-remove').should('not.be.visible') - }) - - it('emits studio:remove:command with number when delete button is clicked', () => { - cy.spy(runner, 'emit') - - cy.contains('#studio-command-parent').closest('.command') - .find('.studio-command-remove').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:remove:command', 7) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/header_spec.ts b/packages/reporter/cypress/integration/header_spec.ts deleted file mode 100755 index 6fb822b4a5..0000000000 --- a/packages/reporter/cypress/integration/header_spec.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from '../../src/runnables/runnables-store' - -const { _ } = Cypress - -describe('header', () => { - let runner: EventEmitter - let runnables: RootRunnable - - beforeEach(() => { - cy.fixture('runnables').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - }) - - describe('tests button', () => { - it('displays tooltip on mouseover', () => { - cy.get('.focus-tests').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'View All Tests F') - }) - - it('focuses tests on click', () => { - cy.spy(runner, 'emit') - // { force: true } is necessary for click to work, apparently because - // of the tooltip popping up and getting in the way - cy.get('.focus-tests button').click({ force: true }) - cy.wrap(runner.emit).should('be.calledWith', 'focus:tests') - }) - - it('shows \'Tests\' when >= 398px wide', () => { - cy.get('.focus-tests span').should('be.visible') - }) - - it('hides \'Tests\' < 398px wide', () => { - cy.viewport(397, 450) - cy.get('.focus-tests span').should('not.be.visible') - }) - }) - - describe('stats', () => { - let addStat: Function - - beforeEach(() => { - addStat = (state: string, times: number) => { - _.times(times, () => { - runner.emit('test:after:run', { state, final: true }) - }) - } - }) - - it('displays numbers for passed, failed, and pending tests', () => { - addStat('passed', 2) - addStat('failed', 3) - addStat('pending', 1) - - cy.get('.passed .num').should('have.text', '2') - cy.get('.failed .num').should('have.text', '3') - cy.get('.pending .num').should('have.text', '1') - - // ensure the page is loaded before taking snapshot - cy.contains('test 4').should('be.visible') - cy.percySnapshot() - }) - - it('displays "--" if zero of the given state', () => { - cy.get('.passed .num').should('have.text', '--') - cy.get('.failed .num').should('have.text', '--') - cy.get('.pending .num').should('have.text', '--') - }) - - it('displays the time taken in seconds', () => { - const start = new Date(2000, 0, 1) - const now = new Date(2000, 0, 1, 0, 0, 12, 340) - - cy.clock(now).then(() => { - runner.emit('reporter:start', { startTime: start.toISOString() }) - }) - - cy.get('.duration .num').should('have.text', '12.34') - }) - - it('displays "--" if no time taken', () => { - cy.get('.duration .num').should('have.text', '--') - }) - }) - - describe('controls', () => { - describe('when running, not paused, and/or without next command', () => { - beforeEach(() => { - runner.emit('run:start') - }) - - describe('auto-scrolling button', () => { - it('is displayed', () => { - cy.get('.toggle-auto-scrolling').should('be.visible') - }) - - it('has auto-scrolling-enabled class when auto-scrolling is enabled', () => { - cy.get('.toggle-auto-scrolling').should('have.class', 'auto-scrolling-enabled') - }) - - it('does not have auto-scrolling-enabled class when auto-scrolling is disabled', () => { - runner.emit('reporter:start', { autoScrollingEnabled: false }) - - cy.get('.toggle-auto-scrolling').should('not.have.class', 'auto-scrolling-enabled') - }) - - it('has tooltip with right title when auto-scrolling is enabled', () => { - cy.get('.toggle-auto-scrolling').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Disable Auto-scrolling A') - }) - - it('has tooltip with right title when auto-scrolling is disabled', () => { - runner.emit('reporter:start', { autoScrollingEnabled: false }) - - cy.get('.toggle-auto-scrolling').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Enable Auto-scrolling A') - }) - - it('emits save:state event when clicked', () => { - cy.spy(runner, 'emit') - cy.get('.toggle-auto-scrolling').click() - cy.wrap(runner.emit).should('be.calledWith', 'save:state') - }) - }) - - describe('stop button', () => { - it('displays stop button', () => { - cy.get('.stop').should('be.visible') - }) - - it('displays tooltip', () => { - cy.get('.stop').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Stop Running S') - }) - - it('emits runner:stop when clicked', () => { - cy.spy(runner, 'emit') - cy.get('.stop').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:stop') - }) - }) - - describe('pause controls', () => { - it('does not display paused label', () => { - cy.get('.paused-label').should('not.exist') - }) - - it('does not display play button', () => { - cy.get('.play').should('not.exist') - }) - - it('does not display restart button', () => { - cy.get('.restart').should('not.exist') - }) - - it('does not display next button', () => { - cy.get('.next').should('not.exist') - }) - }) - }) - - describe('when paused with next command', () => { - beforeEach(() => { - runner.emit('paused', 'find') - }) - - it('displays paused label', () => { - cy.get('.paused-label').should('be.visible') - }) - - it('displays play button', () => { - cy.get('.play').should('be.visible') - }) - - it('displays tooltip for play button', () => { - cy.get('.play').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Resume C') - }) - - it('emits runner:resume when play button is clicked', () => { - cy.spy(runner, 'emit') - cy.get('.play').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:resume') - }) - - it('displays next button', () => { - cy.get('.next').should('be.visible') - }) - - it('displays tooltip for next button', () => { - cy.get('.next').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', `Next [N]:find`) - }) - - it('emits runner:next when next button is clicked', () => { - cy.spy(runner, 'emit') - cy.get('.next').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:next') - }) - - it('does not display stop button', () => { - cy.get('.stop').should('not.exist') - }) - }) - - describe('when not running', () => { - it('displays restart button', () => { - cy.get('.restart').should('be.visible') - }) - - it('displays tooltip for restart button', () => { - cy.get('.restart').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Run All Tests R') - }) - - it('emits runner:restart when restart button is clicked', () => { - cy.spy(runner, 'emit') - cy.get('.restart').click() - cy.wrap(runner.emit).should('be.calledWith', 'runner:restart') - }) - - it('does not display stop button', () => { - cy.get('.stop').should('not.exist') - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/hooks_spec.ts b/packages/reporter/cypress/integration/hooks_spec.ts deleted file mode 100644 index 43860e6164..0000000000 --- a/packages/reporter/cypress/integration/hooks_spec.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from '../../src/runnables/runnables-store' -import { addCommand, itHandlesFileOpening } from '../support/utils' - -describe('hooks', () => { - let runner: EventEmitter - let runnables: RootRunnable - - beforeEach(() => { - cy.fixture('runnables_hooks').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - }) - - describe('general behavior', () => { - beforeEach(() => { - cy.contains('test 1').click() - }) - - it('assigns commands to the correct hook', () => { - cy.contains('before each').closest('.collapsible').find('.command').should('have.length', 2) - cy.contains('before each').closest('.collapsible').should('contain', 'http://localhost:3000') - cy.contains('before each').closest('.collapsible').should('contain', '.wrapper') - - cy.contains('test body').closest('.collapsible').find('.command').should('have.length', 1) - cy.contains('test body').closest('.collapsible').should('contain', '.body') - - cy.contains('after each').closest('.collapsible').find('.command').should('have.length', 1) - cy.contains('after each').closest('.collapsible').should('contain', '.cleanup') - cy.percySnapshot() - }) - - it('displays hooks in the correct order', () => { - const hooks = ['before each', 'test body', 'after each'] - - cy.contains('test 1').closest('.runnable').find('.hook-name').each(($name, i) => { - cy.wrap($name).should('contain', hooks[i]) - }) - }) - - it('displays (failed) next to name for failed hooks', () => { - const err = { - name: 'CypressError', - message: 'Could not find element', - stack: 'Could not find element\n at foo (bar.js:1:2)', - } - - runner.emit('test:after:run', { state: 'failed', id: 'r6', failedFromHookId: 'h3', err }) - - cy.contains('test 2').closest('.runnable').contains('before each') - .find('.hook-failed-message') - .should('be.visible') - }) - - it('does not display (failed) next to name for passed hooks', () => { - cy.contains('test 1').closest('.runnable').contains('before each') - .find('.hook-failed-message') - .should('not.be.visible') - }) - - describe('expanding/collapsing', () => { - it('is expanded by default', () => { - cy.contains('before each').closest('.collapsible').find('.commands-container') - .should('be.visible') - }) - - it('collapses on click', () => { - cy.contains('before each').click() - .closest('.collapsible').find('.commands-container') - .should('not.exist') - }) - - it('expands on second click', () => { - cy.contains('before each').click().click() - .closest('.collapsible').find('.commands-container') - .should('be.visible') - }) - }) - }) - - describe('duplicate hooks', () => { - beforeEach(() => { - cy.contains('test 3').click() - }) - - it('splits different hooks with the same name', () => { - cy.contains('before all (1)').closest('.collapsible').find('.command').should('have.length', 1) - cy.contains('before all (1)').closest('.collapsible').should('contain', 'before1') - - cy.contains('before all (2)').closest('.collapsible').find('.command').should('have.length', 1) - cy.contains('before all (2)').closest('.collapsible').should('contain', 'before2') - - cy.contains('before each (1)').closest('.collapsible').find('.command').should('have.length', 2) - cy.contains('before each (1)').closest('.collapsible').should('contain', 'http://localhost:3000') - cy.contains('before each (1)').closest('.collapsible').should('contain', '.wrapper') - - cy.contains('before each (2)').closest('.collapsible').find('.command').should('have.length', 1) - cy.contains('before each (2)').closest('.collapsible').should('contain', '.header') - }) - - it('does not display hook number when only one', () => { - cy.get('.hooks-container').should('contain', 'after each') - cy.get('.hooks-container').should('not.contain', 'after each (1)') - }) - }) - - describe('open hooks in IDE', () => { - beforeEach(() => { - cy.contains('test 1').click() - }) - - it('does not display button without hover', () => { - cy.contains('Open in IDE').should('not.be.visible') - }) - - it('creates button when hook has invocation details', () => { - cy.contains('before each').closest('.hook-header').should('contain', 'Open in IDE') - }) - - it('creates button when test has invocation details', () => { - cy.contains('test body').closest('.hook-header').should('contain', 'Open in IDE') - }) - - it('does not create button when hook does not have invocation details', () => { - cy.contains('after each').closest('.hook-header').should('not.contain', 'Open in IDE') - }) - - describe('handles file opening', () => { - beforeEach(() => { - cy.get('.hook-open-in-ide').first().invoke('show') - }) - - itHandlesFileOpening({ - getRunner: () => runner, - selector: '.hook-open-in-ide', - file: { - file: '/absolute/path/to/foo_spec.js', - column: 4, - line: 10, - }, - }) - }) - }) - - describe('studio hook', () => { - it('is not visible when not in studio mode', () => { - cy.contains('test 1').click() - - cy.contains('studio commands').should('not.exist') - }) - - describe('with studio active', () => { - beforeEach(() => { - runner.emit('reporter:start', { studioActive: true }) - - cy.contains('test 1').click() - }) - - it('is visible with hook-studio class', () => { - cy.contains('studio commands').should('exist') - .closest('.hook-item').should('have.class', 'hook-studio') - - cy.percySnapshot() - }) - - it('is not visible if test failed', () => { - cy.contains('test 2').closest('.test') - .contains('studio commands').should('not.exist') - }) - - describe('prompt', () => { - it('displays by default and disappears once commands are added', () => { - cy.get('.hook-studio').find('.studio-prompt').should('exist').then(() => { - addCommand(runner, { - id: 1, - hookId: 'r3-studio', - number: 1, - name: 'get', - message: '#studio-command-parent', - state: 'success', - isStudio: true, - type: 'parent', - }) - - addCommand(runner, { - id: 2, - hookId: 'r3-studio', - name: 'click', - message: '#studio-command-child', - state: 'success', - isStudio: true, - type: 'child', - }) - - cy.get('.hook-studio').find('.studio-prompt').should('not.exist') - }) - }) - - it('displays when there is only a visit command and disappears once additional commands are added', () => { - addCommand(runner, { - id: 1, - hookId: 'r3-studio', - number: 1, - name: 'visit', - message: 'the://url', - state: 'success', - type: 'parent', - }) - - cy.get('.hook-studio').find('.studio-prompt').should('exist').then(() => { - addCommand(runner, { - id: 2, - hookId: 'r3-studio', - number: 2, - name: 'get', - message: '#studio-command-parent', - state: 'success', - isStudio: true, - type: 'parent', - }) - - addCommand(runner, { - id: 3, - hookId: 'r3-studio', - name: 'click', - message: '#studio-command-child', - state: 'success', - isStudio: true, - type: 'child', - }) - - cy.get('.hook-studio').find('.studio-prompt').should('not.exist') - }) - }) - - it('does not display when a failed visit command is added', () => { - addCommand(runner, { - id: 1, - hookId: 'r3-studio', - number: 1, - name: 'visit', - message: 'the://url', - state: 'failed', - type: 'parent', - }) - - cy.get('.hook-studio').find('.studio-prompt').should('not.exist') - }) - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/meta_&%_spec.ts b/packages/reporter/cypress/integration/meta_&%_spec.ts deleted file mode 100644 index 863ebf0346..0000000000 --- a/packages/reporter/cypress/integration/meta_&%_spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -// this ensures that special characters in the spec title are displayed -// properly. it tests the actual reporter instead of the AUT like other tests -describe('special characters', () => { - it('displays file name with decoded special characters', () => { - cy.wrap(Cypress.$(window.top.document.body)) - .find('.reporter .runnable-header a') - .should('have.text', 'cypress/integration/meta_&%_spec.ts') - }) -}) diff --git a/packages/reporter/cypress/integration/routes_spec.ts b/packages/reporter/cypress/integration/routes_spec.ts deleted file mode 100644 index c88cc8e4d1..0000000000 --- a/packages/reporter/cypress/integration/routes_spec.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from './../../src/runnables/runnables-store' - -describe('routes', () => { - let runner: EventEmitter - let runnables: RootRunnable - let start: Function - - beforeEach(() => { - cy.fixture('runnables_routes').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - }) - }) - - start = () => { - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - - cy.contains('http://localhost:3000') // ensure test content has loaded - } - }) - - it('does not display if there are no routes', () => { - runnables.tests![0].routes = [] - start() - cy.get('.runnable-routes-region').should('not.be.visible') - }) - - describe('when there are routes', () => { - beforeEach(() => { - start() - }) - - it('displays header with number of routes', () => { - cy.contains('Routes (3)').should('be.visible') - }) - - it('is collapsed by default', () => { - cy.contains('Routes (3)').closest('.runnable-routes-region').find('table') - .should('not.exist') - }) - - it('expands on click', () => { - cy.contains('Routes (3)').click() - cy.contains('Routes (3)').closest('.runnable-routes-region').find('table') - .should('be.visible') - - cy.percySnapshot() - }) - }) - - describe('when routes are expanded', () => { - beforeEach(() => { - start() - cy.contains('Routes (3)').click() - }) - - it('displays tooltip for number of routes', () => { - cy.get('.runnable-routes-region').contains('#').trigger('mouseover') - cy.get('.cy-tooltip') - .should('have.text', 'Number of responses which matched this route') - }) - - it('route displays without no-responses class if numResponses is non-zero', () => { - cy.get('.route-item').first() - .should('not.have.class', 'no-responses') - }) - - it('route displays with no-responses class if zero numResponses', () => { - cy.get('.route-item').eq(1) - .should('have.class', 'no-responses') - }) - - it('route displays the method', () => { - cy.get('.route-item .route-method').first() - .should('have.text', 'GET') - }) - - it('route displays the url', () => { - cy.get('.route-item .route-url').first() - .should('have.text', '/posts') - }) - - it('route displays isStubbed as Yes if stubbed', () => { - cy.get('.route-item .route-is-stubbed').eq(1) - .should('have.text', 'Yes') - }) - - it('route displays isStubbed as No if not stubbed', () => { - cy.get('.route-item .route-is-stubbed').first() - .should('have.text', 'No') - }) - - it('route displays the alias', () => { - cy.get('.route-item .route-alias-name').eq(2) - .should('have.text', 'createPost') - }) - - it('route displays a Tooltip for the alias', () => { - cy.get('.route-item .route-alias-name').eq(2).trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', `Aliased this route as: 'createPost'`) - }) - - it('route displays the numResponses if non-zero', () => { - cy.get('.route-item .route-num-responses').first() - .should('have.text', '2') - }) - - it('route displays the numResponses as "-" if zero', () => { - cy.get('.route-item .route-num-responses').eq(1) - .should('have.text', '-') - }) - }) -}) diff --git a/packages/reporter/cypress/integration/runnables_spec.ts b/packages/reporter/cypress/integration/runnables_spec.ts deleted file mode 100644 index 08ab127d4e..0000000000 --- a/packages/reporter/cypress/integration/runnables_spec.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { EventEmitter } from 'events' -import { RunnablesErrorModel } from '../../src/runnables/runnable-error' -import { RootRunnable } from '../../src/runnables/runnables-store' -import { itHandlesFileOpening } from '../support/utils' - -interface RenderProps { - error?: RunnablesErrorModel -} - -describe('runnables', () => { - let runner: EventEmitter - let runnables: RootRunnable - let render: Function - let start: Function - - beforeEach(() => { - cy.fixture('runnables').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - render = (renderProps: RenderProps = {}) => { - cy.visit('/').then((win) => { - win.render(Object.assign({ - runner, - spec: { - name: 'foo', - absolute: '/foo/bar', - relative: 'foo/bar', - }, - experimentalStudioEnabled: true, - }, renderProps)) - }) - } - - start = (renderProps?: RenderProps) => { - render(renderProps) - - return cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - } - }) - - it('displays loader when runnables have not yet loaded', () => { - render() - cy.contains('Your tests are loading...').should('be.visible') - // ensure the page is loaded before taking snapshot - cy.percySnapshot() - }) - - it('displays runnables when they load', () => { - start() - cy.get('.runnable').should('have.length', 9) - cy.contains('test 4').should('be.visible') - - cy.percySnapshot() - }) - - it('displays multi-spec reporters', () => { - start({ runMode: 'multi', allSpecs: [ - { - relative: 'fizz', - }, - { - relative: 'buzz', - }, - ] }) - - cy.contains('buzz').should('be.visible') - cy.percySnapshot() - }) - - it('displays bundle error if specified', () => { - const error = { - title: 'Oops...we found an error preparing this test file:', - link: 'https://on.cypress.io/we-found-an-error-preparing-your-test-file', - callout: '/path/to/spec', - message: 'We found an error', - } - - start({ error }) - - cy.contains(error.title) - cy.contains(error.callout) - cy.contains(error.message) - - cy.get('.error a').should('have.attr', 'href', error.link) - cy.get('.error a').should('have.attr', 'target', '_blank') - }) - - it('error does not render link if there is not one specified', () => { - const error = { - title: 'Oops...we found an error preparing this test file:', - callout: '/path/to/spec', - message: 'We found an error', - } - - start({ error }) - cy.get('.error a').should('not.exist') - }) - - it('error does not display callout if there is not one specified', () => { - const error = { - title: 'Oops...we found an error preparing this test file:', - message: 'We found an error', - } - - start({ error }) - cy.get('.error pre').should('not.exist') - }) - - it('error displays message with markdown', () => { - const error = { - title: 'Oops...we found an error preparing this test file:', - message: `We **found** an _error_: - - - fix - - it -`, - } - - start({ error }) - cy.get('.error strong').should('have.text', 'found') - cy.get('.error em').should('have.text', 'error') - cy.get('.error li').should('have.length', 2) - }) - - describe('when there are no tests', () => { - beforeEach(() => { - runnables.suites = [] - }) - - it('displays error', () => { - start() - - cy.contains('No tests found.').should('be.visible') - cy.contains('Cypress could not detect tests in this file.').should('be.visible') - cy.contains('Open file in IDE').should('be.visible') - cy.contains('Create test with Cypress Studio').should('be.visible') - cy.get('.help-link').should('have.attr', 'href', 'https://on.cypress.io/intro') - cy.get('.help-link').should('have.attr', 'target', '_blank') - cy.percySnapshot() - }) - - it('does not display links to work with file if running all specs', () => { - start({ - spec: { - name: 'All Integration Specs', - absolute: '__all', - relative: '__all', - }, - }) - - cy.contains('No tests found.').should('be.visible') - cy.contains('Cypress could not detect tests in this file.').should('be.visible') - cy.contains('Open file in IDE').should('not.exist') - cy.contains('Create test with Cypress Studio').should('not.exist') - cy.get('.help-link').should('have.attr', 'href', 'https://on.cypress.io/intro') - cy.get('.help-link').should('have.attr', 'target', '_blank') - }) - - it('can launch studio', () => { - start().then(() => { - cy.stub(runner, 'emit') - - cy.contains('Cypress Studio').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:init:suite', 'r1') - }) - }) - - describe('open in ide', () => { - beforeEach(() => { - start({ - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - }) - }) - - itHandlesFileOpening({ - getRunner: () => runner, - selector: '.no-tests a', - file: { - file: '/absolute/path/to/foo.js', - line: 0, - column: 0, - }, - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/shortcuts_spec.ts b/packages/reporter/cypress/integration/shortcuts_spec.ts deleted file mode 100755 index 0891ee7bd5..0000000000 --- a/packages/reporter/cypress/integration/shortcuts_spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -import sinon, { SinonStub, SinonSpy } from 'sinon' -import { EventEmitter } from 'events' - -type EventEmitterStub = EventEmitter & Stub - -interface Stub { - on: SinonStub - emit: SinonSpy -} - -const runnerStub = () => { - return { - on: sinon.stub(), - emit: sinon.spy(), - } as EventEmitterStub -} - -describe('shortcuts', function () { - let runner: EventEmitterStub - - beforeEach(function () { - runner = runnerStub() - - cy.fixture('runnables').as('runnables') - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', this.runnables) - runner.emit('reporter:start', {}) - }) - }) - - describe('shortcuts', () => { - it('stops tests', () => { - cy.get('body').then(() => { - expect(runner.emit).not.to.have.been.calledWith('runner:stop') - }) - - cy.get('body').type('s').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:stop') - }) - }) - - it('does not stop tests when paused', () => { - cy.get('body').then(() => { - expect(runner.emit).not.to.have.been.calledWith('runner:stop') - }) - - runner.on.withArgs('paused').callArgWith(1, 'next command') - - cy.get('body').type('s').then(() => { - expect(runner.emit).not.to.have.been.calledWith('runner:stop') - }) - }) - - it('resumes tests', () => { - cy.get('body').then(() => { - expect(runner.emit).not.to.have.been.calledWith('runner:restart') - }) - - cy.get('body').type('r').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:restart') - }) - }) - - it('focuses on specs', () => { - cy.get('body').then(() => { - expect(runner.emit).not.to.have.been.calledWith('focus:tests') - }) - - cy.get('body').type('f').then(() => { - expect(runner.emit).to.have.been.calledWith('focus:tests') - }) - }) - - it('continues resuming tests', () => { - cy.get('body').type('s').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:stop') - }) - - cy.get('body').type('c').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:resume') - }) - }) - - it('go to next test', () => { - cy.get('body').type('s').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:stop') - }) - - cy.get('body').type('n').then(() => { - expect(runner.emit).to.have.been.calledWith('runner:next') - }) - }) - - it('toggles auto-scrolling', () => { - cy.get('body').type('a') - cy.get('.toggle-auto-scrolling').should('not.have.class', 'auto-scrolling-enabled') - cy.get('body').type('a') - cy.get('.toggle-auto-scrolling').should('have.class', 'auto-scrolling-enabled') - }) - - it('does not run shortcut if typed into an input', () => { - cy.get('body') - .then(($body) => { - // this realistically happens with the selector playground, but - // need to add an input since this environment is isolated - $body.append('') - }) - .get('#temp-input').type('r', { force: true }) - .then(() => { - expect(runner.emit).not.to.have.been.calledWith('runner:restart') - }) - }) - - it('has shortcut in tooltips', () => { - cy.get('.focus-tests > button').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'View All Tests F') - cy.get('.focus-tests > button').trigger('mouseout') - - cy.get('button.restart').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Run All Tests R') - - cy.window().then((win) => win.state.isRunning = true) - cy.get('button.stop').trigger('mouseover') - cy.get('.cy-tooltip').should('have.text', 'Stop Running S') - }) - - it('does not run shortcut if modifier keys are pressed', () => { - ['{ctrl+f}', '{alt+f}', '{shift+f}', '{meta+f}'].forEach((text) => { - cy.get('body').type(text) - }) - - cy.then(() => { - expect(runner.emit).not.to.have.been.calledWith('focus:tests') - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/spec_title_spec.ts b/packages/reporter/cypress/integration/spec_title_spec.ts deleted file mode 100644 index e0448a1cab..0000000000 --- a/packages/reporter/cypress/integration/spec_title_spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { EventEmitter } from 'events' -import { itHandlesFileOpening } from '../support/utils' - -describe('spec title', () => { - let runner: EventEmitter - let start: Function - - beforeEach(() => { - runner = new EventEmitter() - - start = (spec: Cypress.Cypress['spec']) => { - cy.visit('/').then((win) => { - win.render({ runner, spec }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', {}) - runner.emit('reporter:start', {}) - }) - } - }) - - it('all specs displays "All Specs"', () => { - start({ - relative: '__all', - name: '', - absolute: '__all', - }) - - cy.get('.runnable-header').should('have.text', 'All Specs') - - cy.percySnapshot() - }) - - it('all specs displays "Specs matching ..."', () => { - start({ - relative: '__all', - name: '', - absolute: '__all', - specFilter: 'cof', - }) - - cy.contains('.runnable-header', 'Specs matching "cof"') - - cy.percySnapshot() - }) - - describe('single spec', () => { - beforeEach(() => { - start({ - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }) - }) - - it('displays relative spec path', () => { - cy.get('.runnable-header').find('a').should('have.text', 'relative/path/to/foo.js') - - cy.percySnapshot() - }) - - it('displays tooltip on hover', () => { - cy.get('.runnable-header a').first().trigger('mouseover') - cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') - }) - - itHandlesFileOpening({ - getRunner: () => runner, - selector: '.runnable-header a', - file: { - file: '/absolute/path/to/foo.js', - line: 0, - column: 0, - }, - }) - }) -}) diff --git a/packages/reporter/cypress/integration/suites_spec.ts b/packages/reporter/cypress/integration/suites_spec.ts deleted file mode 100644 index b75c0d818d..0000000000 --- a/packages/reporter/cypress/integration/suites_spec.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from '../../src/runnables/runnables-store' - -describe('suites', () => { - let runner: EventEmitter - let runnables: RootRunnable - - beforeEach(() => { - cy.fixture('runnables').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - experimentalStudioEnabled: true, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - }) - - it('includes the class "suite"', () => { - cy.contains('suite 1') - .closest('.runnable') - .should('have.class', 'suite') - - // ensure the page is loaded before taking snapshot - cy.contains('test 4').should('be.visible') - cy.percySnapshot() - }) - - it('includes the state as a class', () => { - cy.contains('suite 1') - .closest('.runnable') - .should('have.class', 'runnable-failed') - - cy.contains('suite 2') - .closest('.runnable') - .should('have.class', 'runnable-passed') - }) - - describe('expand and collapse', () => { - it('is expanded by default', () => { - cy.contains('suite 1') - .parents('.collapsible').as('suiteWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('be.visible') - }) - - describe('expand/collapse suite manually', () => { - beforeEach(() => { - cy.contains('suite 1') - .parents('.collapsible').as('suiteWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content') - .should('be.visible') - }) - - it('expands/collapses on click', () => { - cy.contains('suite 1') - .click() - - cy.get('@suiteWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('not.be.visible') - - cy.contains('suite 1') - .click() - - cy.get('@suiteWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('be.visible') - }) - - it('expands/collapses on enter', () => { - cy.contains('suite 1') - .parents('.collapsible-header') - .focus().type('{enter}') - - cy.get('@suiteWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('not.be.visible') - - cy.contains('suite 1') - .parents('.collapsible-header') - .focus().type('{enter}') - - cy.get('@suiteWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('be.visible') - }) - - it('expands/collapses on space', () => { - cy.contains('suite 1') - .parents('.collapsible-header') - .focus().type(' ') - - cy.get('@suiteWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('not.be.visible') - - cy.contains('suite 1') - .parents('.collapsible-header') - .focus().type(' ') - - cy.get('@suiteWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').eq(0) - .should('be.visible') - }) - }) - }) - - describe('studio button', () => { - it('displays studio icon with half transparency when hovering over test title', () => { - cy.contains('suite 1') - .closest('.runnable-wrapper') - .realHover() - .find('.runnable-controls-studio') - .should('be.visible') - .should('have.css', 'opacity', '0.5') - }) - - it('displays studio icon with no transparency and tooltip on hover', () => { - cy.contains('suite 1') - .closest('.collapsible-header') - .find('.runnable-controls-studio') - .realHover() - .should('be.visible') - .should('have.css', 'opacity', '1') - - cy.get('.cy-tooltip').contains('Add New Test') - }) - - it('emits studio:init:suite with the suite id when clicked', () => { - cy.stub(runner, 'emit') - - cy.contains('suite 1').parents('.collapsible-header') - .find('.runnable-controls-studio').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:init:suite', 'r2') - }) - }) -}) diff --git a/packages/reporter/cypress/integration/test_errors_spec.ts b/packages/reporter/cypress/integration/test_errors_spec.ts deleted file mode 100644 index 0c1f633742..0000000000 --- a/packages/reporter/cypress/integration/test_errors_spec.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { EventEmitter } from 'events' -import { itHandlesFileOpening } from '../support/utils' -import Err from '../../src/errors/err-model' -import { RootRunnable } from '../../src/runnables/runnables-store' - -describe('test errors', () => { - let commandErr: Partial - let setError: Function - let runnablesWithErr: RootRunnable - let runner: EventEmitter - - beforeEach(() => { - cy.fixture('runnables_error').then((_runnablesWithErr) => runnablesWithErr = _runnablesWithErr) - cy.fixture('command_error').then((_commandErr) => commandErr = _commandErr) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - setError = (err: Error) => { - // @ts-ignore - runnablesWithErr.suites[0].tests[0].err = err - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnablesWithErr) - runner.emit('reporter:start', {}) - }) - } - - win.render({ - runner, - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - }) - }) - }) - - describe('print to console', () => { - beforeEach(() => { - setError(commandErr) - }) - - it('clicking prints to console', () => { - cy.spy(runner, 'emit') - cy.get('.runnable-err-print').click().should(() => { - expect(runner.emit).to.be.calledWith('runner:console:error') - - // @ts-ignore - const err = runner.emit.withArgs('runner:console:error').lastCall.args[1].err - - expect(err.message).to.equal(commandErr.message) - expect(err.stack).to.equal(commandErr.stack) - }) - }) - - it('shows popup confirming output was printed', () => { - cy.get('.runnable-err-print').click() - cy.contains('Printed output to your console') - }) - - it('does not collapse test when clicking', () => { - cy.get('.runnable-err-print').click() - cy.get('.command-wrapper').should('be.visible') - }) - - it('does not expand or collapse stack trace when clicking', () => { - cy.get('.runnable-err-print').click() - cy.get('.runnable-err-stack-trace').should('not.be.visible') - cy.contains('View stack trace').click() - cy.get('.runnable-err-stack-trace').should('be.visible') - cy.get('.runnable-err-print').click() - cy.get('.runnable-err-stack-trace').should('be.visible') - }) - }) - - describe('stack trace', () => { - beforeEach(() => { - setError(commandErr) - }) - - it('hides stack trace by default', () => { - cy.get('.runnable-err-stack-trace').should('not.be.visible') - }) - - it('opens stack trace on click', () => { - cy.contains('View stack trace').click() - cy.get('.runnable-err-stack-trace').should('be.visible') - cy.percySnapshot() - }) - - it('pairs down stack line whitespace', () => { - cy.contains('View stack trace').click() - - cy.get('.runnable-err-stack-trace').within(() => { - cy.get('.err-stack-line') - .should('have.length', 10) - .first().should('have.text', 'at foo.bar (my/app.js:2:7)') - - cy.get('.err-stack-line') - .eq(1).should('have.text', ' at baz.qux (cypress/integration/foo_spec.js:5:2)') - - cy.get('.err-stack-line') - .eq(2).should('have.text', ' at space (cypress/integration/a b.js:34:99)') - - cy.get('.err-stack-line') - .eq(3).should('have.text', 'At previous event:') - - cy.get('.err-stack-line') - .eq(4).should('have.text', ' at bar.baz (http://localhost:1234/me/dev/my/app.js:8:11)') - - cy.get('.err-stack-line') - .eq(5).should('have.text', ' at callFn (cypress://../driver/src/cypress/runner.js:9:12)') - }) - }) - - it('does not include message in stack trace', () => { - cy.contains('View stack trace').click() - cy.get('.runnable-err-stack-trace') - .invoke('text') - .should('not.include', 'Some Error') - .should('not.include', 'Message line below blank line') - }) - - it('turns files into links', () => { - cy.contains('View stack trace').click() - - cy.get('.runnable-err-stack-trace .runnable-err-file-path') - .should('have.length', 3) - .first() - .should('have.text', 'my/app.js:2:7') - - cy.get('.runnable-err-stack-trace .runnable-err-file-path').eq(1) - .should('have.text', 'cypress/integration/foo_spec.js:5:2') - - cy.get('.runnable-err-stack-trace .runnable-err-file-path').eq(2) - .should('have.text', 'cypress/integration/a b.js:34:99') - }) - - it('does not turn cypress:// files into links', () => { - cy.contains('View stack trace').click() - cy.contains('cypress://').find('a').should('not.exist') - }) - - it('does not turn cypress_runner.js files into links', () => { - cy.contains('View stack trace').click() - cy.contains('cypress_runner.js').find('a').should('not.exist') - }) - - it('does not turn lines without absoluteFile into links', () => { - cy.contains('View stack trace').click() - cy.contains('.err-stack-line', 'http://localhost:1234/me/dev/my/app.js:8:11') - .find('a').should('not.exist') - }) - - it('does not turn anything after "From Node.js Internals" into links', () => { - cy.contains('View stack trace').click() - cy.contains('events.js').find('a').should('not.exist') - cy.contains('node/internals.js').find('a').should('not.exist') - }) - - it('does not collapse test when clicking', () => { - cy.contains('View stack trace').click() - cy.get('.command-wrapper').should('be.visible') - }) - - it('displays tooltip on hover', () => { - cy.contains('View stack trace').click() - - cy.get('.runnable-err-stack-trace a').first().trigger('mouseover') - cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') - }) - - itHandlesFileOpening({ - getRunner: () => runner, - selector: '.runnable-err-stack-trace a', - file: { - file: '/me/dev/my/app.js', - line: 2, - column: 7, - }, - stackTrace: true, - }) - }) - - describe('command error', () => { - it('shows error name', () => { - setError(commandErr) - - cy.get('.runnable-err-name').should('contain', commandErr.name) - }) - - it('renders and escapes markdown', () => { - setError(commandErr) - - cy.get('.runnable-err-message') - - // renders `foo` as foo - .contains('code', 'foo') - .then((content) => { - expect(content).not.to.contain('`foo`') - }) - - // renders /`bar/` as `bar` - cy.get('.runnable-err-message') - .should('contain', '`bar`') - - // renders **baz** as baz - cy.get('.runnable-err-message') - .contains('strong', 'baz') - .then((content) => { - expect(content).not.to.contain('**baz**') - }) - - // renders *fizz* as fizz - cy.get('.runnable-err-message') - .contains('em', 'fizz') - .then((content) => { - expect(content).not.to.contain('*fizz*') - }) - - cy.percySnapshot() - }) - - // NOTE: still needs to be implemented - it.skip('renders and escapes markdown with leading/trailing whitespace', () => { - cy.get('.runnable-err-message') - - // https://github.com/cypress-io/cypress/issues/1360 - // renders ** buzz ** as buzz - .contains('code', 'foo') - .and('not.contain', '`foo`') - }) - }) - - describe('code frames', () => { - beforeEach(() => { - setError(commandErr) - }) - - it('shows code frame when included on error', () => { - cy - .get('.test-err-code-frame') - .should('be.visible') - - cy.percySnapshot() - }) - - it('use correct language class', () => { - cy - .get('.test-err-code-frame pre') - .should('have.class', 'language-javascript') - }) - - it('displays tooltip on hover', () => { - cy.get('.test-err-code-frame a').first().trigger('mouseover') - cy.get('.cy-tooltip').first().should('have.text', 'Open in IDE') - }) - - itHandlesFileOpening({ - getRunner: () => runner, - selector: '.test-err-code-frame a', - file: { - file: '/me/dev/my/app.js', - line: 2, - column: 7, - }, - }) - }) - - describe('code frames', () => { - it('does not show code frame when not included on error', () => { - commandErr.codeFrame = undefined - setError(commandErr) - - cy - .get('.test-err-code-frame') - .should('not.exist') - }) - - it('falls back to text language class', () => { - // @ts-ignore - commandErr.codeFrame.language = null - setError(commandErr) - cy - .get('.test-err-code-frame pre') - .should('have.class', 'language-text') - }) - }) - - describe('studio error', () => { - beforeEach(() => { - setError(runnablesWithErr) - }) - - it('is not visible by default', () => { - cy.get('.studio-err-wrapper').should('not.be.visible') - }) - - it('is visible when studio is active', () => { - runner.emit('reporter:start', { studioActive: true }) - - cy.get('.studio-err-wrapper').should('be.visible') - - cy.percySnapshot() - }) - }) -}) diff --git a/packages/reporter/cypress/integration/tests_spec.ts b/packages/reporter/cypress/integration/tests_spec.ts deleted file mode 100644 index 72a8789305..0000000000 --- a/packages/reporter/cypress/integration/tests_spec.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { EventEmitter } from 'events' -import { RootRunnable } from '../../src/runnables/runnables-store' -import { addCommand } from '../support/utils' - -describe('tests', () => { - let runner: EventEmitter - let runnables: RootRunnable - - const addStudioCommand = () => { - addCommand(runner, { - hookId: 'r3-studio', - name: 'get', - message: '#studio-command', - state: 'success', - isStudio: true, - }) - } - - beforeEach(() => { - cy.fixture('runnables').then((_runnables) => { - runnables = _runnables - }) - - runner = new EventEmitter() - - cy.visit('/').then((win) => { - win.render({ - runner, - spec: { - name: 'foo.js', - relative: 'relative/path/to/foo.js', - absolute: '/absolute/path/to/foo.js', - }, - experimentalStudioEnabled: true, - }) - }) - - cy.get('.reporter').then(() => { - runner.emit('runnables:ready', runnables) - runner.emit('reporter:start', {}) - }) - }) - - it('includes the class "test"', () => { - cy.contains('test 1') - .closest('.runnable') - .should('have.class', 'test') - }) - - it('includes the state as a class', () => { - cy.contains('suite 1') - .closest('.runnable') - .should('have.class', 'runnable-failed') - - cy.contains('suite 2') - .closest('.runnable') - .should('have.class', 'runnable-passed') - }) - - describe('expand and collapse', () => { - beforeEach(() => { - cy.contains('test 1') - .parents('.collapsible').first().as('testWrapper') - }) - - it('is collapsed by default', () => { - cy.contains('test 1') - .parents('.collapsible').first() - .should('not.have.class', 'is-open') - .find('.collapsible-content') - .should('not.be.visible') - }) - - it('failed tests expands automatically', () => { - cy.contains('test 2') - .parents('.collapsible').first() - .should('have.class', 'is-open') - .find('.collapsible-content') - .should('be.visible') - }) - - it('expands/collapses on click', () => { - cy.contains('test 1') - .click() - - cy.get('@testWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').should('be.visible') - - cy.contains('test 1') - .click() - - cy.get('@testWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').should('not.be.visible') - }) - - it('expands/collapses on enter', () => { - cy.contains('test 1') - .parents('.collapsible-header').first() - .focus().type('{enter}') - - cy.get('@testWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').should('be.visible') - - cy.contains('test 1') - .parents('.collapsible-header').first() - .focus().type('{enter}') - - cy.get('@testWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').should('not.be.visible') - }) - - it('expands/collapses on space', () => { - cy.contains('test 1') - .parents('.collapsible-header').first() - .focus().type(' ') - - cy.get('@testWrapper') - .should('have.class', 'is-open') - .find('.collapsible-content').should('be.visible') - - cy.contains('test 1') - .parents('.collapsible-header').first() - .focus().type(' ') - - cy.get('@testWrapper') - .should('not.have.class', 'is-open') - .find('.collapsible-content').should('not.be.visible') - }) - }) - - describe('studio', () => { - describe('button', () => { - it('displays studio icon with half transparency when hovering over test title', () => { - cy.contains('test 1') - .closest('.runnable-wrapper') - .realHover() - .find('.runnable-controls-studio') - .should('be.visible') - .should('have.css', 'opacity', '0.5') - }) - - it('displays studio icon with no transparency and tooltip on hover', () => { - cy.contains('test 1') - .closest('.collapsible-header') - .find('.runnable-controls-studio') - .realHover() - .should('be.visible') - .should('have.css', 'opacity', '1') - - cy.get('.cy-tooltip').contains('Add Commands to Test') - }) - - it('emits studio:init:test with the suite id when studio button clicked', () => { - cy.stub(runner, 'emit') - - cy.contains('test 1').parents('.collapsible-header') - .find('.runnable-controls-studio').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:init:test', 'r3') - }) - }) - - describe('controls', () => { - it('is not visible by default', () => { - cy.contains('test 1').click() - .parents('.collapsible').first() - .find('.studio-controls').should('not.exist') - }) - - describe('with studio active', () => { - beforeEach(() => { - runner.emit('reporter:start', { studioActive: true }) - - cy.contains('test 1').click() - .parents('.collapsible').first() - .find('.studio-controls').as('studioControls') - }) - - it('is visible with save and copy button when test passed', () => { - cy.get('@studioControls').should('be.visible') - cy.get('@studioControls').find('.studio-save').should('be.visible') - cy.get('@studioControls').find('.studio-copy').should('be.visible') - - cy.percySnapshot() - }) - - it('is visible without save and copy button if test failed', () => { - cy.contains('test 2') - .parents('.collapsible').first() - .find('.studio-controls').should('be.visible') - - cy.contains('test 2') - .parents('.collapsible').first() - .find('.studio-save').should('not.be.visible') - - cy.contains('test 2') - .parents('.collapsible').first() - .find('.studio-copy').should('not.be.visible') - }) - - it('is visible without save and copy button if test was skipped', () => { - cy.contains('nested suite 1') - .parents('.collapsible').first() - .contains('test 1').click() - .parents('.collapsible').first() - .find('.studio-controls').as('pendingControls') - .should('be.visible') - - cy.get('@pendingControls').find('.studio-save').should('not.be.visible') - cy.get('@pendingControls').find('.studio-copy').should('not.be.visible') - }) - - it('is not visible while test is running', () => { - cy.contains('nested suite 1') - .parents('.collapsible').first() - .contains('test 2').click() - .parents('.collapsible').first() - .find('.studio-controls').should('not.be.visible') - }) - - it('emits studio:cancel when cancel button clicked', () => { - cy.stub(runner, 'emit') - - cy.get('@studioControls').find('.studio-cancel').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:cancel') - }) - - describe('copy button', () => { - it('is disabled without tooltip when there are no commands', () => { - cy.get('@studioControls') - .find('.studio-copy') - .should('be.disabled') - .parent('span') - .trigger('mouseover') - - cy.get('.cy-tooltip').should('not.exist') - }) - - it('is enabled with tooltip when there are commands', () => { - addStudioCommand() - - cy.get('@studioControls') - .find('.studio-copy') - .should('not.be.disabled') - .trigger('mouseover') - - cy.get('.cy-tooltip').should('have.text', 'Copy Commands to Clipboard') - }) - - it('is emits studio:copy:to:clipboard when clicked', () => { - addStudioCommand() - - cy.stub(runner, 'emit') - - cy.get('@studioControls').find('.studio-copy').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:copy:to:clipboard') - }) - - it('displays success state after commands are copied', () => { - addStudioCommand() - - cy.stub(runner, 'emit').callsFake((event, callback) => { - if (event === 'studio:copy:to:clipboard') { - callback('') - } - }) - - cy.get('@studioControls') - .find('.studio-copy') - .click() - .should('have.class', 'studio-copy-success') - .trigger('mouseover') - - cy.get('.cy-tooltip').should('have.text', 'Commands Copied!') - }) - }) - - describe('save button', () => { - it('is disabled without commands', () => { - cy.get('@studioControls').find('.studio-save').should('be.disabled') - }) - - it('is enabled when there are commands', () => { - addStudioCommand() - - cy.get('@studioControls').find('.studio-save').should('not.be.disabled') - }) - - it('is emits studio:save when clicked', () => { - addStudioCommand() - - cy.stub(runner, 'emit') - - cy.get('@studioControls').find('.studio-save').click() - - cy.wrap(runner.emit).should('be.calledWith', 'studio:save') - }) - }) - }) - }) - }) -}) diff --git a/packages/reporter/cypress/integration/unit/app_state_spec.ts b/packages/reporter/cypress/integration/unit/app_state_spec.ts deleted file mode 100644 index 4c43bdd049..0000000000 --- a/packages/reporter/cypress/integration/unit/app_state_spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -import appState, { AppState } from '../../../src/lib/app-state' - -describe('app state', () => { - it('exports singleton by default', () => { - expect(appState).to.be.instanceof(AppState) - }) - - context('#startRunning', () => { - it('sets isRunning to true', () => { - const instance = new AppState() - - instance.startRunning() - expect(instance.isRunning).to.be.true - }) - - it('sets isStopped to false', () => { - const instance = new AppState() - - instance.isStopped = true - instance.startRunning() - expect(instance.isStopped).to.be.false - }) - }) - - context('#pause', () => { - it('sets isPaused to true', () => { - const instance = new AppState() - - instance.pause() - expect(instance.isPaused).to.be.true - }) - - it('sets the next command name', () => { - const instance = new AppState() - - instance.pause('next command') - expect(instance.nextCommandName).to.equal('next command') - }) - }) - - context('#resume', () => { - it('sets isPaused to false', () => { - const instance = new AppState() - - instance.resume() - expect(instance.isPaused).to.be.false - }) - - it('unsets the next command name', () => { - const instance = new AppState() - - instance.resume() - expect(instance.nextCommandName).to.be.null - }) - }) - - context('#stop', () => { - it('sets isStopped to true', () => { - const instance = new AppState() - - instance.stop() - expect(instance.isStopped).to.be.true - }) - }) - - context('#end', () => { - it('sets isRunning to false', () => { - const instance = new AppState() - - instance.end() - expect(instance.isRunning).to.be.false - }) - - it('resets autoScrollingEnabled', () => { - const instance = new AppState() - - instance.temporarilySetAutoScrolling(false) - instance.end() - expect(instance.autoScrollingEnabled).to.be.true - }) - }) - - context('#temporarilySetAutoScrolling', () => { - it('sets autoScrollingEnabled to boolean specified', () => { - const instance = new AppState() - - instance.temporarilySetAutoScrolling(false) - expect(instance.autoScrollingEnabled).to.be.false - }) - - it('does nothing if argument is null', () => { - const instance = new AppState() - - instance.temporarilySetAutoScrolling(null) - expect(instance.autoScrollingEnabled).to.be.true - }) - - it('does nothing if argument is undefined', () => { - const instance = new AppState() - - instance.temporarilySetAutoScrolling() - expect(instance.autoScrollingEnabled).to.be.true - }) - }) - - context('#setAutoScrolling', () => { - it('sets autoScrollingEnabled', () => { - const instance = new AppState() - - instance.setAutoScrolling(false) - expect(instance.autoScrollingEnabled).to.be.false - instance.setAutoScrolling(true) - expect(instance.autoScrollingEnabled).to.be.true - }) - - it('sets reset value for autoScrollingEnabled', () => { - const instance = new AppState() - - instance.setAutoScrolling(false) - instance.reset() - expect(instance.autoScrollingEnabled).to.be.false - }) - }) - - context('#toggleAutoScrolling', () => { - it('toggles autoScrollingEnabled', () => { - const instance = new AppState() - - instance.toggleAutoScrolling() - expect(instance.autoScrollingEnabled).to.be.false - instance.toggleAutoScrolling() - expect(instance.autoScrollingEnabled).to.be.true - }) - - it('sets reset value for autoScrollingEnabled', () => { - const instance = new AppState() - - instance.toggleAutoScrolling() - instance.reset() - expect(instance.autoScrollingEnabled).to.be.false - }) - }) - - context('#setStudioActive', () => { - it('sets studioActive', () => { - const instance = new AppState() - - instance.setStudioActive(true) - expect(instance.studioActive).to.eq(true) - instance.setStudioActive(false) - expect(instance.studioActive).to.eq(false) - }) - }) - - context('#reset', () => { - it('resets autoScrollingEnabled when it has not been toggled', () => { - const instance = new AppState() - - instance.temporarilySetAutoScrolling(false) - instance.reset() - expect(instance.autoScrollingEnabled).to.be.true - }) - - it('does not reset autoScrollingEnabled when it has been toggled', () => { - const instance = new AppState() - - instance.toggleAutoScrolling() - instance.reset() - expect(instance.autoScrollingEnabled).to.be.false - }) - - it('sets isPaused to false', () => { - const instance = new AppState() - - instance.isPaused = true - instance.reset() - expect(instance.isPaused).to.be.false - }) - - it('sets isRunning to false', () => { - const instance = new AppState() - - instance.isRunning = true - instance.reset() - expect(instance.isRunning).to.be.false - }) - - it('sets nextCommandName to null', () => { - const instance = new AppState() - - instance.nextCommandName = 'next command' - instance.reset() - expect(instance.nextCommandName).to.be.null - }) - - it('sets pinnedSnapshotId to null', () => { - const instance = new AppState() - - instance.pinnedSnapshotId = 'c4' - instance.reset() - expect(instance.pinnedSnapshotId).to.be.null - }) - - it('sets studioActive to false', () => { - const instance = new AppState() - - instance.studioActive = true - instance.reset() - expect(instance.studioActive).to.be.false - }) - }) -}) diff --git a/packages/reporter/cypress/integration/unit/events_spec.ts b/packages/reporter/cypress/integration/unit/events_spec.ts deleted file mode 100644 index 3c3c8320c0..0000000000 --- a/packages/reporter/cypress/integration/unit/events_spec.ts +++ /dev/null @@ -1,404 +0,0 @@ -import sinon, { SinonSpy, SinonStub } from 'sinon' - -import events from '../../../src/lib/events' -import { AppState } from '../../../src/lib/app-state' -import { RunnablesStore } from '../../../src/runnables/runnables-store' -import { Scroller } from '../../../src/lib/scroller' -import { StatsStore } from '../../../src/header/stats-store' - -interface RunnerStub { - on: SinonSpy - emit: SinonSpy -} - -const runnerStub = (): RunnerStub => { - return { - on: sinon.stub(), - emit: sinon.spy(), - } -} - -type AppStateStub = AppState & { - startRunning: SinonSpy - pause: SinonSpy - reset: SinonSpy - resume: SinonSpy - end: SinonSpy - temporarilySetAutoScrolling: SinonSpy - setStudioActive: SinonSpy - stop: SinonSpy -} - -const appStateStub = () => { - return { - startRunning: sinon.spy(), - pause: sinon.spy(), - reset: sinon.spy(), - resume: sinon.spy(), - end: sinon.spy(), - temporarilySetAutoScrolling: sinon.spy(), - setStudioActive: sinon.spy(), - stop: sinon.spy(), - } as AppStateStub -} - -type RunnablesStoreStub = RunnablesStore & { - addLog: SinonSpy - reset: SinonSpy - runnableStarted: SinonSpy - runnableFinished: SinonSpy - setInitialScrollTop: SinonStub - setRunnables: SinonSpy - testById: SinonStub - updateLog: SinonSpy - removeLog: SinonSpy -} - -const runnablesStoreStub = () => { - return { - addLog: sinon.spy(), - reset: sinon.spy(), - runnableStarted: sinon.spy(), - runnableFinished: sinon.spy(), - setInitialScrollTop: sinon.stub(), - setRunnables: sinon.spy(), - testById: sinon.stub(), - updateLog: sinon.spy(), - removeLog: sinon.spy(), - } as RunnablesStoreStub -} - -type ScrollerStub = Scroller & { - getScrollTop: SinonStub -} - -const scrollerStub = () => { - return { - getScrollTop: sinon.stub(), - } as ScrollerStub -} - -type StatsStoreStub = StatsStore & { - incrementCount: SinonSpy - pause: SinonSpy - reset: SinonSpy - resume: SinonSpy - start: SinonSpy - startRunning: SinonSpy - end: SinonSpy -} - -const statsStoreStub = () => { - return { - incrementCount: sinon.spy(), - pause: sinon.spy(), - reset: sinon.spy(), - resume: sinon.spy(), - start: sinon.spy(), - startRunning: sinon.spy(), - end: sinon.spy(), - } as StatsStoreStub -} - -describe('events', () => { - let appState: AppStateStub - let runnablesStore: RunnablesStoreStub - let scroller: ScrollerStub - let statsStore: StatsStoreStub - let runner: RunnerStub - - beforeEach(() => { - events.__off() - - appState = appStateStub() - runnablesStore = runnablesStoreStub() - scroller = scrollerStub() - statsStore = statsStoreStub() - events.init({ appState, runnablesStore, scroller, statsStore }) - - runner = runnerStub() - events.listen(runner) - }) - - context('from runner', () => { - it('sets runnables on runnables:ready', () => { - runner.on.withArgs('runnables:ready').callArgWith(1, 'root runnable') - expect(runnablesStore.setRunnables).to.have.been.calledWith('root runnable') - }) - - it('adds log on reporter:log:add', () => { - runner.on.withArgs('reporter:log:add').callArgWith(1, 'the log') - expect(runnablesStore.addLog).to.have.been.calledWith('the log') - }) - - it('updates log on reporter:log:state:changed', () => { - runner.on.withArgs('reporter:log:state:changed').callArgWith(1, 'the updated log') - expect(runnablesStore.updateLog).to.have.been.calledWith('the updated log') - }) - - it('deletes log on reporter:log:remove', () => { - runner.on.withArgs('reporter:log:remove').callArgWith(1, 'the deleted log') - expect(runnablesStore.removeLog).to.have.been.calledWith('the deleted log') - }) - - it('resets runnables on reporter:restart:test:run', () => { - runner.on.withArgs('reporter:restart:test:run').callArgWith(1) - expect(runnablesStore.reset).to.have.been.called - }) - - it('resets stats on reporter:restart:test:run', () => { - runner.on.withArgs('reporter:restart:test:run').callArgWith(1) - expect(statsStore.reset).to.have.been.called - }) - - it('resets appState on reporter:restart:test:run', () => { - runner.on.withArgs('reporter:restart:test:run').callArgWith(1) - expect(appState.reset).to.have.been.called - }) - - it('emits reporter:restarted on reporter:restart:test:run', () => { - runner.on.withArgs('reporter:restart:test:run').callArgWith(1) - expect(runner.emit).to.have.been.calledWith('reporter:restarted') - }) - - it('starts running stats on run:start if there are tests', () => { - runnablesStore.hasTests = true - runner.on.withArgs('run:start').callArgWith(1) - expect(appState.startRunning).to.have.been.called - }) - - it('does not start running stats on run:start if there are no tests', () => { - runnablesStore.hasTests = false - runner.on.withArgs('run:start').callArgWith(1) - expect(appState.startRunning).not.to.have.been.called - }) - - it('starts stats on reporter:start', () => { - runnablesStore.hasTests = true - runner.on.withArgs('reporter:start').callArgWith(1, {}) - expect(statsStore.start).to.have.been.calledWith({}) - }) - - it('does not start stats if there are no tests on reporter:start', () => { - runnablesStore.hasTests = false - runner.on.withArgs('reporter:start').callArgWith(1, {}) - expect(statsStore.start).not.to.have.been.called - }) - - it('sets autoScrollingEnabled on the app state on reporter:start', () => { - runner.on.withArgs('reporter:start').callArgWith(1, { autoScrollingEnabled: false }) - expect(appState.temporarilySetAutoScrolling).to.have.been.calledWith(false) - }) - - it('sets studioActive on the app state on reporter:start', () => { - runner.on.withArgs('reporter:start').callArgWith(1, { studioActive: true }) - expect(appState.setStudioActive).to.have.been.calledWith(true) - }) - - it('sets initial scrollTop on the scroller on reporter:start', () => { - runner.on.withArgs('reporter:start').callArgWith(1, { scrollTop: 123 }) - expect(runnablesStore.setInitialScrollTop).to.have.been.calledWith(123) - }) - - it('sends runnable started on test:before:run:async', () => { - runner.on.withArgs('test:before:run:async').callArgWith(1, 'the runnable') - expect(runnablesStore.runnableStarted).to.have.been.calledWith('the runnable') - }) - - it('sends runnable finished on test:after:run', () => { - runner.on.withArgs('test:after:run').callArgWith(1, 'the runnable') - expect(runnablesStore.runnableFinished).to.have.been.calledWith('the runnable') - }) - - it('increments the stats count on test:after:run if final: true', () => { - runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed', final: true }) - expect(statsStore.incrementCount).to.have.been.calledWith('passed') - }) - - it('does not increment the stats count on test:after:run if not final: true', () => { - runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed' }) - expect(statsStore.incrementCount).not.to.have.been.called - }) - - it('does not increment the stats count if studio is active', () => { - appState.studioActive = true - runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed', final: true }) - expect(statsStore.incrementCount).not.to.have.been.calledWith('passed') - }) - - it('pauses the appState with next command name on paused', () => { - runner.on.withArgs('paused').callArgWith(1, 'next command') - expect(appState.pause).to.have.been.calledWith('next command') - }) - - it('pauses the stats on paused', () => { - runner.on.withArgs('paused').callArgWith(1, 'next command') - expect(statsStore.pause).to.have.been.called - }) - - it('ends the appState on run:end', () => { - runner.on.withArgs('run:end').callArgWith(1) - expect(appState.end).to.have.been.called - }) - - it('ends the stats on run:end', () => { - runner.on.withArgs('run:end').callArgWith(1) - expect(statsStore.end).to.have.been.called - }) - - it('calls callback with scrollTop and autoScrollingEnabled on reporter:collect:run:state', () => { - const callback = sinon.spy() - - appState.autoScrollingEnabled = false - scroller.getScrollTop.returns(321) - runner.on.withArgs('reporter:collect:run:state').callArgWith(1, callback) - expect(callback).to.have.been.calledWith({ - autoScrollingEnabled: false, - scrollTop: 321, - }) - }) - - it('nullifies the appState pinned snapshot id on reporter:snapshot:unpinned', () => { - appState.pinnedSnapshotId = 'c1' - runner.on.withArgs('reporter:snapshot:unpinned').callArgWith(1) - expect(appState.pinnedSnapshotId).to.be.null - }) - }) - - context('from local bus', () => { - it('resumes the appState on resume', () => { - events.emit('resume') - expect(appState.resume).to.have.been.called - }) - - it('resumes the stats on resume', () => { - events.emit('resume') - expect(statsStore.resume).to.have.been.called - }) - - it('emits runner:resume on resume', () => { - events.emit('resume') - expect(runner.emit).to.have.been.calledWith('runner:resume') - }) - - it('emits runner:next on next', () => { - events.emit('next') - expect(runner.emit).to.have.been.calledWith('runner:next') - }) - - it('stops the appState on stop', () => { - events.emit('stop') - expect(appState.stop).to.have.been.called - }) - - it('emits runner:stop on stop', () => { - events.emit('stop') - expect(runner.emit).to.have.been.calledWith('runner:stop') - }) - - it('emits runner:restart on restart', () => { - events.emit('restart') - expect(runner.emit).to.have.been.calledWith('runner:restart') - }) - - it('emits runner:console:log on show:command', () => { - events.emit('show:command', 'command id') - expect(runner.emit).to.have.been.calledWith('runner:console:log', 'command id') - }) - - it('emits runner:console:error with test id on show:error', () => { - const test = { err: { isCommandErr: false } } - - runnablesStore.testById.returns(test) - events.emit('show:error', test) - expect(runner.emit).to.have.been.calledWith('runner:console:error', { - err: test.err, - commandId: undefined, - }) - }) - - it('emits runner:console:error with test id and command id on show:error when it is a command error and there is a matching command', () => { - const test = { err: { isCommandErr: true }, commandMatchingErr: () => { - return { id: 'matching command id' } - } } - - runnablesStore.testById.returns(test) - events.emit('show:error', test) - expect(runner.emit).to.have.been.calledWith('runner:console:error', { - err: test.err, - commandId: 'matching command id', - }) - }) - - it('emits runner:console:error with test id on show:error when it is a command error but there not a matching command', () => { - const test = { err: { isCommandErr: true }, commandMatchingErr: () => { - return null - } } - - runnablesStore.testById.returns(test) - events.emit('show:error', test) - expect(runner.emit).to.have.been.calledWith('runner:console:error', { - err: test.err, - commandId: undefined, - }) - }) - - it('emits runner:show:snapshot on show:snapshot', () => { - events.emit('show:snapshot', 'command id') - expect(runner.emit).to.have.been.calledWith('runner:show:snapshot', 'command id') - }) - - it('emits runner:hide:snapshot on hide:snapshot', () => { - events.emit('hide:snapshot', 'command id') - expect(runner.emit).to.have.been.calledWith('runner:hide:snapshot', 'command id') - }) - - it('emits runner:pin:snapshot on pin:snapshot', () => { - events.emit('pin:snapshot', 'command id') - expect(runner.emit).to.have.been.calledWith('runner:pin:snapshot', 'command id') - }) - - it('emits runner:unpin:snapshot on unpin:snapshot', () => { - events.emit('unpin:snapshot', 'command id') - expect(runner.emit).to.have.been.calledWith('runner:unpin:snapshot', 'command id') - }) - - it('emits focus:tests on focus:tests', () => { - events.emit('focus:tests') - expect(runner.emit).to.have.been.calledWith('focus:tests') - }) - - it('emits save:state on save:state', () => { - appState.autoScrollingEnabled = false - events.emit('save:state') - expect(runner.emit).to.have.been.calledWith('save:state', { - autoScrollingEnabled: false, - }) - }) - - it('emits studio:init:test with test id on studio:init:test', () => { - events.emit('studio:init:test', 'test id') - expect(runner.emit).to.have.been.calledWith('studio:init:test', 'test id') - }) - - it('emits studio:init:suite with test id on studio:init:suite', () => { - events.emit('studio:init:suite', 'suite id') - expect(runner.emit).to.have.been.calledWith('studio:init:suite', 'suite id') - }) - - it('emits studio:remove:command with command id on studio:remove:command', () => { - events.emit('studio:remove:command', 'command id') - expect(runner.emit).to.have.been.calledWith('studio:remove:command', 'command id') - }) - - it('emits studio:cancel on studio:cancel', () => { - events.emit('studio:cancel') - expect(runner.emit).to.have.been.calledWith('studio:cancel') - }) - - it('emits studio:save on studio:save', () => { - events.emit('studio:save') - expect(runner.emit).to.have.been.calledWith('studio:save') - }) - }) -}) diff --git a/packages/reporter/cypress/plugins/index.ts b/packages/reporter/cypress/plugins/index.ts deleted file mode 100644 index 1aadc59a5a..0000000000 --- a/packages/reporter/cypress/plugins/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -// const cp = require('child_process') - -// cp.exec('http-server -p 5006 dist') - -const express = require('express') - -express().use(express.static('dist')).listen(5006) -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on: Function) => { -} diff --git a/packages/reporter/cypress/support/e2e.ts b/packages/reporter/cypress/support/e2e.ts new file mode 100644 index 0000000000..6ce0e6acdc --- /dev/null +++ b/packages/reporter/cypress/support/e2e.ts @@ -0,0 +1,13 @@ +import 'cypress-real-events/support' +// @ts-ignore +import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand' + +installCustomPercyCommand({ + before () { + cy.get('.toggle-specs-text').should('be.visible') + }, + elementOverrides: { + '.command-progress': true, + '.cy-tooltip': true, + }, +}) diff --git a/packages/reporter/cypress/support/index.ts b/packages/reporter/cypress/support/index.ts deleted file mode 100644 index cc311b25f1..0000000000 --- a/packages/reporter/cypress/support/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import 'cypress-real-events/support' -// @ts-ignore -import installCustomPercyCommand from '@packages/ui-components/cypress/support/customPercyCommand' - -installCustomPercyCommand({ - before () { - cy.get('.focus-tests-text').should('be.visible') - }, - elementOverrides: { - '.command-progress': true, - '.cy-tooltip': true, - }, -}) diff --git a/packages/reporter/cypress/support/utils.ts b/packages/reporter/cypress/support/utils.ts index 8f1a0db837..1ac9af04de 100644 --- a/packages/reporter/cypress/support/utils.ts +++ b/packages/reporter/cypress/support/utils.ts @@ -1,5 +1,4 @@ import { EventEmitter } from 'events' -import { Editor } from '@packages/ui-components' import CommandModel from './../../src/commands/command-model' const { _ } = Cypress @@ -18,131 +17,16 @@ interface HandlesFileOpeningProps { } export const itHandlesFileOpening = ({ getRunner, selector, file, stackTrace = false }: HandlesFileOpeningProps) => { - beforeEach(() => { - cy.stub(getRunner(), 'emit').callThrough() - }) - - describe('when user has already set opener and opens file', () => { - let editor: Partial - - beforeEach(() => { - editor = {} - - // @ts-ignore - getRunner().emit.withArgs('get:user:editor').yields({ - preferredOpener: editor, - }) + describe('it handles file opening', () => { + it('emits unified file open event', () => { + cy.stub(getRunner(), 'emit').callThrough() if (stackTrace) { cy.contains('View stack trace').click() } - }) - it('opens in preferred opener', () => { cy.get(selector).first().click().then(() => { - expect(getRunner().emit).to.be.calledWith('open:file', { - where: editor, - ...file, - }) - }) - }) - }) - - describe('when user has not already set opener and opens file', () => { - const availableEditors = [ - { id: 'computer', name: 'On Computer', isOther: false, openerId: 'computer' }, - { id: 'atom', name: 'Atom', isOther: false, openerId: 'atom' }, - { id: 'vim', name: 'Vim', isOther: false, openerId: 'vim' }, - { id: 'sublime', name: 'Sublime Text', isOther: false, openerId: 'sublime' }, - { id: 'vscode', name: 'Visual Studio Code', isOther: false, openerId: 'vscode' }, - { id: 'other', name: 'Other', isOther: true, openerId: '' }, - ] - - beforeEach(() => { - // @ts-ignore - getRunner().emit.withArgs('get:user:editor').yields({ availableEditors }) - // usual viewport of only reporter is a bit cramped for the modal - cy.viewport(600, 600) - - if (stackTrace) { - cy.contains('View stack trace').click() - } - - cy.get(selector).first().click() - }) - - it('opens modal with available editors', () => { - _.each(availableEditors, ({ name }) => { - cy.contains(name) - }) - - cy.contains('Other') - cy.contains('Set preference and open file') - }) - - // NOTE: this fails because mobx doesn't make the editors observable, so - // the changes to the path don't bubble up correctly. this only happens - // in the Cypress test and not when running the actual app - it.skip('updates "Other" path when typed into', () => { - cy.contains('Other').find('input[type="text"]').type('/absolute/path/to/foo.js') - .should('have.value', '/absolute/path/to/foo.js') - }) - - describe('when editor is not selected', () => { - it('disables submit button', () => { - cy.contains('Set preference and open file') - .should('have.class', 'is-disabled') - .click() - - cy.wrap(getRunner().emit).should('not.to.be.calledWith', 'set:user:editor') - cy.wrap(getRunner().emit).should('not.to.be.calledWith', 'open:file') - }) - - it('shows validation message when hovering over submit button', () => { - cy.get('.editor-picker-modal .submit').trigger('mouseover') - cy.get('.cy-tooltip').last().should('have.text', 'Please select a preference') - }) - }) - - describe('when Other is selected but path is not entered', () => { - beforeEach(() => { - cy.contains('Other').click() - }) - - it('disables submit button', () => { - cy.contains('Set preference and open file') - .should('have.class', 'is-disabled') - .click() - - cy.wrap(getRunner().emit).should('not.to.be.calledWith', 'set:user:editor') - cy.wrap(getRunner().emit).should('not.to.be.calledWith', 'open:file') - }) - - it('shows validation message when hovering over submit button', () => { - cy.get('.editor-picker-modal .submit').trigger('mouseover') - cy.get('.cy-tooltip').last().should('have.text', 'Please enter the path for the "Other" editor') - }) - }) - - describe('when editor is set', () => { - beforeEach(() => { - cy.contains('Visual Studio Code').click() - cy.contains('Set preference and open file').click() - }) - - it('closes modal', function () { - cy.contains('Set preference and open file').should('not.exist') - }) - - it('emits set:user:editor', () => { - expect(getRunner().emit).to.be.calledWith('set:user:editor', availableEditors[4]) - }) - - it('opens file in selected editor', () => { - expect(getRunner().emit).to.be.calledWith('open:file', { - where: availableEditors[4], - ...file, - }) + expect(getRunner().emit).to.be.calledWith('open:file:unified') }) }) }) diff --git a/packages/reporter/index.d.ts b/packages/reporter/index.d.ts index 3c6f8f3f73..e930058784 100644 --- a/packages/reporter/index.d.ts +++ b/packages/reporter/index.d.ts @@ -16,3 +16,8 @@ declare namespace Cypress { percySnapshot (): Chainable } } + +declare module "*.svg" { + const content: any; + export default content; +} diff --git a/packages/reporter/package.json b/packages/reporter/package.json index fa38d2a24a..b1938055c4 100644 --- a/packages/reporter/package.json +++ b/packages/reporter/package.json @@ -5,7 +5,7 @@ "browser": "src/main.tsx", "scripts": { "build-for-tests": "webpack", - "clean-deps": "rm -rf node_modules", + "clean-deps": "rimraf node_modules", "cypress:open": "node ../../scripts/cypress open --project .", "cypress:run": "node ../../scripts/cypress run --project .", "watch": "yarn build-for-tests --watch --progress" @@ -14,7 +14,7 @@ "@cypress/react-tooltip": "0.5.3", "@fontsource/mulish": "4.3.0", "@fontsource/open-sans": "4.3.0", - "@fortawesome/fontawesome-free": "5.11.2", + "@fortawesome/fontawesome-free": "6.0.0", "@packages/driver": "0.0.0-development", "@packages/resolve-dist": "0.0.0-development", "@packages/socket": "0.0.0-development", @@ -24,7 +24,7 @@ "classnames": "2.3.1", "css-element-queries": "1.2.3", "cypress-multi-reporters": "1.4.0", - "cypress-real-events": "1.4.0", + "cypress-real-events": "1.6.0", "lodash": "^4.17.21", "markdown-it": "11.0.0", "mobx": "5.15.4", @@ -33,8 +33,10 @@ "prop-types": "15.7.2", "react": "16.8.6", "react-dom": "16.8.6", + "react-svg-loader": "3.0.3", + "rimraf": "3.0.2", "sinon": "7.5.0", - "webpack": "4.35.3", + "webpack": "^4.44.2", "webpack-cli": "3.3.2" }, "files": [] diff --git a/packages/reporter/src/.eslintrc.json b/packages/reporter/src/.eslintrc.json index debcccc97d..726a9b3103 100644 --- a/packages/reporter/src/.eslintrc.json +++ b/packages/reporter/src/.eslintrc.json @@ -9,7 +9,17 @@ "version": "16.12" } }, + "plugins": [ + "import" + ], "rules": { + "no-duplicate-imports": "off", + "import/no-duplicates": [ + "error", + { + "considerQueryString": true + } + ], "arrow-body-style": "off", "no-unused-vars": "off", "react/jsx-filename-extension": [ diff --git a/packages/reporter/src/agents/agents.tsx b/packages/reporter/src/agents/agents.tsx index 2a0a09e9b2..52ddb3bdee 100644 --- a/packages/reporter/src/agents/agents.tsx +++ b/packages/reporter/src/agents/agents.tsx @@ -13,7 +13,7 @@ export interface AgentProps { const Agent = observer(({ model }: AgentProps) => ( - {model.type} + {model.name} {model.functionName} {([] as Array).concat(model.alias || []).join(', ')} {model.callCount || '-'} @@ -51,7 +51,7 @@ const Agents = observer(({ model }: AgentsProps) => ( - + {/* the spy/stub's name provided by the driver */} diff --git a/packages/reporter/src/attempts/attempt-model.ts b/packages/reporter/src/attempts/attempt-model.ts index 51b956b1ed..27fe8b8227 100644 --- a/packages/reporter/src/attempts/attempt-model.ts +++ b/packages/reporter/src/attempts/attempt-model.ts @@ -7,7 +7,7 @@ import Err from '../errors/err-model' import Route, { RouteProps } from '../routes/route-model' import Test, { UpdatableTestProps, TestProps, TestState } from '../test/test-model' import Hook, { HookName } from '../hooks/hook-model' -import { FileDetails } from '@packages/ui-components' +import { FileDetails } from '@packages/types' import { LogProps } from '../runnables/runnables-store' import Log from '../instruments/instrument-model' import Session, { SessionProps } from '../sessions/sessions-model' diff --git a/packages/reporter/src/attempts/attempts.scss b/packages/reporter/src/attempts/attempts.scss index c574e32cef..230f3d32ae 100644 --- a/packages/reporter/src/attempts/attempts.scss +++ b/packages/reporter/src/attempts/attempts.scss @@ -20,9 +20,9 @@ } &:before { - border-left: 1px solid #dcdcdc; + border-left: 1px solid $gray-900; content: ''; - left: 5px; + left: 9px; position: absolute; top: 22px; height: 15px; @@ -38,57 +38,36 @@ } > .is-open .open-close-indicator { - i.fa-angle-down { - margin-top: 0; - } - - i.fa-angle-up { - order: 1; - margin-top: -4px; - } + svg.collapse-icon { + display: block; } - .open-close-indicator { - display: flex; - flex-direction: column; + svg.expand-icon { + display: none; + } + } - i { - margin-right: 5px; + .open-close-indicator { + svg { + margin-right: 3px; - &.fa-angle-down { - margin-top: -4px; - } + &.collapse-icon { + display: none; + } + + &.expand-icon { + display: block; } } } +} - - .attempt-state-active { - .attempt-state { - @include runnable-state-active; - } - } - .attempt-state-processing { - .attempt-state { - @include runnable-state-processing; - } - } .attempt-state-failed { - .attempt-state { - @include runnable-state-failed; - } - .attempt-name:after { color: $fail; } } .attempt-state-passed { - .attempt-state { - - @include runnable-state-passed; - } - - .attempt-name:after { color: $pass; } @@ -102,7 +81,7 @@ width: 100%; &:before { - border-top: 1px solid #dcdcdc; + border-top: 1px solid $gray-900; content: ''; left: 15px; position: absolute; @@ -111,28 +90,28 @@ } &:after { - color: #a2a2a2; + color: $gray-600; content: 'โ€ข'; - left: 3px; + left: 7px; position: absolute; - top: 6px; + top: 4px; } .attempt-tag { align-items: center; - border: 1px solid #d5d5d5; + border: 1px solid $gray-900; border-radius: 7px; - box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.20); + box-shadow: 0 1px 1px 0 rgba($white, 0.20); display: flex; font-size: 11px; padding: 2px 5px; position: relative; - background-color: #fff; + background-color: $black; user-select: none; cursor: pointer; &:hover { - background-color: #e8e8e8; + background-color: $gray-1000; } } diff --git a/packages/reporter/src/attempts/attempts.tsx b/packages/reporter/src/attempts/attempts.tsx index 7a8b6f1379..9dbdbe2219 100644 --- a/packages/reporter/src/attempts/attempts.tsx +++ b/packages/reporter/src/attempts/attempts.tsx @@ -1,5 +1,4 @@ import cs from 'classnames' -import _ from 'lodash' import { observer } from 'mobx-react' import React, { Component } from 'react' @@ -8,10 +7,14 @@ import Collapsible from '../collapsible/collapsible' import Hooks from '../hooks/hooks' import Routes from '../routes/routes' import TestError from '../errors/test-error' -import TestModel from '../test/test-model' +import TestModel, { TestState } from '../test/test-model' import AttemptModel from './attempt-model' import Sessions from '../sessions/sessions' +import CollapseIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/collapse_x16.svg' +import ExpandIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/expand_x16.svg' +import StateIcon from '../lib/state-icon' + const NoCommands = () => (
  • @@ -20,14 +23,14 @@ const NoCommands = () => (
) -const AttemptHeader = ({ index }: {index: number}) => ( +const AttemptHeader = ({ index, state }: {index: number, state: TestState }) => ( - - + + Attempt {index + 1} - + ) @@ -43,7 +46,6 @@ const StudioError = () => ( function renderAttemptContent (model: AttemptModel) { // performance optimization - don't render contents if not open - return (
@@ -52,7 +54,6 @@ function renderAttemptContent (model: AttemptModel) {
{model.hasCommands ? : }
-
@@ -87,7 +88,7 @@ class Attempt extends Component { ref="container" > } + header={} headerClass='attempt-name' isOpen={model.isOpen} > @@ -102,7 +103,7 @@ const Attempts = observer(({ test, scrollIntoView }: {test: TestModel, scrollInt return (
    - {_.map(test.attempts, (attempt) => { + {test.attempts.map((attempt) => { return ( .collapsible-header-wrapper > .collapsible-header > .collapsible-header-inner > .collapsible-indicator { - @extend .#{$fa-css-prefix}-caret-down; + transform: rotate(0); } } diff --git a/packages/reporter/src/collapsible/collapsible.tsx b/packages/reporter/src/collapsible/collapsible.tsx index c9d0533d65..ee4814e15f 100644 --- a/packages/reporter/src/collapsible/collapsible.tsx +++ b/packages/reporter/src/collapsible/collapsible.tsx @@ -3,6 +3,8 @@ import React, { Component, CSSProperties, MouseEvent, ReactNode, RefObject } fro import { onEnterOrSpace } from '../lib/util' +import ChevronIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/chevron-down-small_x8.svg' + interface Props { isOpen?: boolean headerClass?: string @@ -54,7 +56,7 @@ class Collapsible extends Component { style={this.props.headerStyle} tabIndex={-1} > - + {this.props.header} diff --git a/packages/reporter/src/commands/command-model.ts b/packages/reporter/src/commands/command-model.ts index 387bd21480..b9e7095acf 100644 --- a/packages/reporter/src/commands/command-model.ts +++ b/packages/reporter/src/commands/command-model.ts @@ -127,6 +127,7 @@ export default class Command extends Instrument { this.group = props.group this.hasSnapshot = !!props.hasSnapshot this.hasConsoleProps = !!props.hasConsoleProps + this._checkLongRunning() } diff --git a/packages/reporter/src/commands/command.tsx b/packages/reporter/src/commands/command.tsx index 019fdd0b8b..d43f06ed12 100644 --- a/packages/reporter/src/commands/command.tsx +++ b/packages/reporter/src/commands/command.tsx @@ -3,8 +3,7 @@ import cs from 'classnames' import Markdown from 'markdown-it' import { action, observable } from 'mobx' import { observer } from 'mobx-react' -import React, { Component, MouseEvent } from 'react' -// @ts-ignore +import React, { Component } from 'react' import Tooltip from '@cypress/react-tooltip' import appState, { AppState } from '../lib/app-state' @@ -17,16 +16,17 @@ import { Alias, AliasObject } from '../instruments/instrument-model' import CommandModel from './command-model' import TestError from '../errors/test-error' +import ChevronIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/chevron-down-small_x8.svg' +import HiddenIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/general-eye-closed_x16.svg' +import PinIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/object-pin_x16.svg' +import RunningIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/status-running_x16.svg' + const md = new Markdown() const displayName = (model: CommandModel) => model.displayName || model.name const nameClassName = (name: string) => name.replace(/(\s+)/g, '-') const formattedMessage = (message: string) => message ? md.renderInline(message) : '' const invisibleMessage = (model: CommandModel) => { - if (model.visible) { - return '' - } - return model.numElements > 1 ? 'One or more matched elements are not visible.' : 'This element is not visible.' @@ -47,6 +47,26 @@ const shouldShowCount = (aliasesWithDuplicates: Array | null, aliasName: return _.includes(aliasesWithDuplicates, aliasName) } +const CommandColumn = observer(({ model }) => { + if (model.hasChildren) { + return ( +
    + +
    + ) + } + + return ( +
    + {} + {model._isPending() && } + {!model._isPending() && {model.number || ''}} +
    + ) +}) + interface AliasReferenceProps { aliasObj: AliasObject model: CommandModel @@ -80,7 +100,7 @@ interface AliasesReferencesProps { const AliasesReferences = observer(({ model, aliasesWithDuplicates }: AliasesReferencesProps) => ( {_.map(([] as Array).concat((model.referencesAlias as AliasObject)), (aliasObj) => ( - + ))} @@ -117,20 +137,22 @@ const Interceptions = observer(({ model }: InterceptionsProps) => { return ( - 1 && 'show-count')}>{model.renderProps.status ? {model.renderProps.status} : null}{displayAlias || no alias} - {count > 1 ? {count} : null} + 1 && 'show-count')}> + {model.renderProps.status && {model.renderProps.status} } + {displayAlias || no alias} + + {count > 1 && {count}} ) }) interface AliasesProps { - isOpen: boolean model: CommandModel aliasesWithDuplicates: Array | null } -const Aliases = observer(({ model, aliasesWithDuplicates, isOpen }: AliasesProps) => { +const Aliases = observer(({ model, aliasesWithDuplicates }: AliasesProps) => { if (!model.alias || model.aliasType === 'route') return null return ( @@ -138,7 +160,7 @@ const Aliases = observer(({ model, aliasesWithDuplicates, isOpen }: AliasesProps {_.map(([] as Array).concat(model.alias), (alias) => { const aliases = [alias] - if (!isOpen && model.hasChildren) { + if (model.hasChildren && !model.isOpen) { aliases.push(..._.compact(model.children.map((dupe) => dupe.alias))) } @@ -160,11 +182,17 @@ interface MessageProps { const Message = observer(({ model }: MessageProps) => ( - + {!!model.renderProps.indicator && ( + + )} { } const commandName = model.name ? nameClassName(model.name) : '' + const displayNumOfElements = model.state !== 'pending' && model.numElements != null && model.numElements !== 1 const isSystemEvent = model.type === 'system' && model.event const isSessionCommand = commandName === 'session' const displayNumOfChildren = !isSystemEvent && !isSessionCommand && model.hasChildren && !model.isOpen @@ -235,22 +264,8 @@ class Command extends Component { className={cs( 'command', `command-name-${commandName}`, - `command-state-${model.state}`, - `command-type-${model.type}`, { - 'command-is-studio': model.isStudio, - 'command-is-event': !!model.event, - 'command-is-invisible': !model.visible, - 'command-has-num-elements': model.state !== 'pending' && model.numElements != null, - 'command-is-pinned': this._isPinned(), - 'command-with-indicator': !!model.renderProps.indicator, 'command-scaled': message && message.length > 100, - 'no-elements': !model.numElements, - 'command-has-snapshot': model.hasSnapshot, - 'command-has-console-props': model.hasConsoleProps, - 'multiple-elements': model.numElements > 1, - 'command-has-children': model.hasChildren, - 'command-is-open': this._isOpen(), }, )} > @@ -259,69 +274,73 @@ class Command extends Component { onClick={this._onClick} shouldShowMessage={this._shouldShowClickMessage} > -
    this._snapshot(true)} onMouseLeave={() => this._snapshot(false)} >
    - - - - - - {model.number || ''} - - {!model.hasChildren && ( - - - - )} + - {model.event && model.type !== 'system' ? `(${displayName(model)})` : displayName(model)} + + {model.event && model.type !== 'system' ? `(${displayName(model)})` : displayName(model)} + - {model.referencesAlias ? : } + {model.referencesAlias ? + + : + } - - - - - - {model.numElements} - + {(model.visible != null && !model.visible) && ( + + + + + + )} + {displayNumOfElements && ( + + {model.numElements} + + )} - + {displayNumOfChildren && ( - 1 })}>{model.numChildren} + + {model.numChildren} + )} -
    -
    - {this._children()} + {(model.hasChildren && model.isOpen) && this._children()} ) } - _isOpen () { - const { model } = this.props - - return !!model.isOpen - } - _children () { const { appState, events, model, runnablesStore } = this.props - if (!this._isOpen()) return - return (
      {_.map(model.children, (child) => ( @@ -352,14 +371,14 @@ class Command extends Component { } @action _onClick = () => { + if (this.props.appState.isRunning) return + if (this.props.model.hasChildren) { this.props.model.toggleOpen() return } - if (this.props.appState.isRunning || this.props.appState.studioActive) return - const { id } = this.props.model if (this._isPinned()) { @@ -421,17 +440,6 @@ class Command extends Component { }, 50) } } - - _removeStudioCommand = (e: MouseEvent) => { - e.preventDefault() - e.stopPropagation() - - const { model, events } = this.props - - if (!model.isStudio) return - - events.emit('studio:remove:command', model.number) - } } export { Aliases, AliasesReferences, Message, Progress } diff --git a/packages/reporter/src/commands/commands.scss b/packages/reporter/src/commands/commands.scss index a45fc013a2..cf8363070d 100644 --- a/packages/reporter/src/commands/commands.scss +++ b/packages/reporter/src/commands/commands.scss @@ -1,6 +1,8 @@ .reporter { + // rendered within ../hooks/hooks.tsx .commands-container { font-family: $monospace; + background-color: $reporter-section-background; min-width: $reporter-contents-min-width; padding: 0; @@ -10,9 +12,9 @@ } .command { - background-color: #eef1f4; + background-color: $reporter-section-background; cursor: default; - margin: 0; + min-height: 20px; } .command-scaled { @@ -20,279 +22,155 @@ line-height: 14px; } - .command-is-studio { - cursor: auto; - - &.command-type-parent .command-controls .studio-command-remove { - display: block; - padding-left: 5px; - - &:hover { - color: #565554; - } - } - - .command-wrapper:hover { - background-color: #eef1f4; - } - } - - .hook-studio { - .command-wrapper:hover { - background-color: #eef1f4; - } - - .command-type-parent > span > .command-wrapper { - &:hover { - border-top: 1px solid #e3e3e3; - } - } - - .command-type-parent:first-child > span > .command-wrapper { - border-top: 0; - } - } - - .command-type-system.command-is-event > span > .command-wrapper { + // System Command Styles + .command-type-system.command-is-event { user-select: none; font-style: unset; + .command-method, .command-message { - color: #525252; + color: $gray-200; font-weight: 700; } } - .command-is-event > span > .command-wrapper { + + // Event Styles + .command-is-event { font-style: italic; .command-method, .command-message { - color: #9a9aaa; + color: $gray-500; } } - .command-type-parent > span > .command-wrapper { - border-top: 1px solid #e3e3e3; - - &:hover { - border-top: 1px solid #eef1f4; - } - } - - .command-type-parent:first-child > span > .command-wrapper { - border-top: 0; - } - - .command-type-child > span > div > div > .command-method { - &:before { - float: left; - content: "-"; - margin-right: 2px; - padding-left: 5px; + // Child Styles + .command-type-child { + .command-method { + &:before { + float: left; + content: "-"; + margin-right: 2px; + padding-left: 5px; + } } } .command-wrapper { - background-color: #eef1f4; - color: #777; + color: $gray-400; min-height: 20px; &:hover { - background-color: #e0e5e7; + background-color: $gray-900; + + .command-pin + .command-number { + display: none; + } + + .command-pin { + display: block; + } + + .command-expander > path { + stroke: $gray-500; + } } .command-wrapper-text { display: flex; flex-wrap: wrap; - padding: 2px 5px 0; + padding: 2px 5px 0 3px; + } - .command-interceptions { - font-style: normal; + .command-interceptions { + font-style: normal; - .status { - font-weight: 600; - } + .status { + font-weight: 600; + } + } + + .command-alias, + .command-interceptions { + border-radius: 10px; + color: $gray-400; + padding: 0 5px; + display: inline-block; + + &.route { + background-color: $yellow-medium; } - .command-alias, - .command-interceptions { - border-radius: 10px; - color: #777888; - padding: 0 5px; - display: inline-block; - - &.route { - background-color: $yellow-medium; - } - - &.dom { - background-color: darken(#d4eaff, 3%); - } - - &.agent, - &.primitive { - background-color: darken(#ffe0de, 3%); - } - - &.show-count { - padding-right: 2px; - border-radius: 10px 0 0 10px; - max-width: 200px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - vertical-align: top; - height: 18px; - } + &.dom { + background-color: $indigo-800; } - // ensures alias & number of children commands don't break if reporter - // width is narrow - .alias-container { + &.agent, + &.primitive { + background-color: $red-800; + } + + &.show-count { + padding-right: 2px; + border-radius: 10px 0 0 10px; + max-width: 200px; white-space: nowrap; - - > { - display: inline-block; - } + overflow: hidden; + text-overflow: ellipsis; + vertical-align: top; + height: 18px; } + } - .num-children, - .command-alias-count .command-interceptions-count { - border-radius: 5px; - color: #777; - font-size: 90%; - font-style: normal; - line-height: 1; - margin-left: 0; - } + // ensures alias & number of children commands don't break if reporter + // width is narrow + .alias-container { + white-space: nowrap; - .num-children.has-alias { - border-radius: 10px; - line-height: 1; - padding: 3px 5px 3px 5px; + > { + display: inline-block; } + } - .command-interceptions-count { - border-radius: 0 10px 10px 0; - padding: 2px 5px; - } + .num-children, + .command-alias-count, + .command-interceptions-count { + background-color: $orange-700 !important; + border-radius: 5px; + color: $gray-400; + font-size: 90%; + font-style: normal; + line-height: 1; + margin-left: 0; + } - .command-alias-count { - border-radius: 0 10px 10px 0; - padding: 2px 5px; - } + .num-children.has-alias { + border-radius: 10px; + line-height: 1; + padding: 3px 5px 3px 5px; + } - .num-children, - .command-alias-count, - .command-interceptions-count { - background-color: darken(#ffdf9c, 8%) !important; - } + .command-alias-count, + .command-interceptions-count { + border-radius: 0 10px 10px 0; + padding: 2px 5px; } .command-progress { height: 2px; } } + .command-child-container { margin-left: 10px; } - .command-number { + .command-number-column { flex-shrink: 0; - color: #bcbccc; min-height: 1px; // because some numbers are empty padding-right: 10px; text-align: right; width: 25px; - - i { - display: none; - } - } - - .command-state-pending > span > .command-wrapper .command-number { - i { - line-height: 18px; - display: inline-block; - } - - span { - display: none; - } - } - - .command-method { - padding: 1px 2px 0; - display: inline-block; - font-size: 11px; - min-width: 80px; - font-weight: 600; - color: #565554; - } - - .command-state-pending > span > .command-wrapper { - border-left: 2px solid $pending; - background-color: lighten($pending, 40%); - cursor: default; - - &:hover { - box-shadow: none; - } - - .command-wrapper-text { - padding-left: 3px; - - .command-number { - margin-left: 5px; - width: 20px; - } - - .command-number, - .command-method, - .command-message, - .command-pin { - color: lighten($pending, 15%); - } - } - - .command-progress > span { - animation-fill-mode: forwards; - animation-iteration-count: 1; - animation-name: progress-bar; - animation-timing-function: linear; - background: #7eb0db; - display: block; - float: right; - height: 100%; - width: 100%; - transform-origin: right; - - @keyframes progress-bar { - 100% { - transform: scaleX(0); - } - } - } - } - - .command-state-failed > span > .command-wrapper { - border-left: 2px solid $fail; - background-color: $err-header-background; - - &:hover { - background: darken($err-header-background, 2%); - } - - .command-wrapper-text { - padding-left: 3px; - - .command-number, - .command-method, - .command-message, - .command-pin { - color: $err-header-text; - } - } } .command-message { @@ -304,6 +182,28 @@ > span { align-items: center; display: flex; + + .fa-circle { + padding: 4px; + padding-right: 2px; + display: inline-block; + } + + .fa-circle.command-message-indicator-successful { + color: $pending; + } + + .fa-circle.command-message-indicator-aborted { + color: $fail; + } + + .fa-circle.command-message-indicator-bad { + color: $orange-500; + } + + .fa-circle.command-message-indicator-pending { + color: $gray-500; + } } } @@ -314,24 +214,99 @@ text-overflow: ellipsis; } - .command-wrapper { - .fa-circle { - display: none; + .command-method { + padding: 1px 2px 0; + display: inline-block; + font-size: 11px; + min-width: 80px; + font-weight: 600; + } + + // Command State Styles + .command-state-passed { + border-left: 2px solid $reporter-section-background; + + &:hover { + border-left: 2px solid $gray-900; + } + + .command-pin { + color: $gray-500; + } + + &:not(.command-is-event) .command-number { + color: $gray-700; + } + + &:not(.command-is-event) .command-method { + color: $gray-200; + } + + .command-message { + color: $gray-400; } } - .command-state-warn > span > .command-wrapper { + .command-state-pending { + border-left: 2px solid $indigo-800; + background-color: $gray-900; + cursor: default; + color: $indigo-200; + + .command-number-column { + .command-pin { + display: none; + } + + .fa-circle { + line-height: 18px; + display: inline-block; + + .icon-light { + stroke: $gray-800; + } + } + } + + .command-progress > span { + animation-fill-mode: forwards; + animation-iteration-count: 1; + animation-name: progress-bar; + animation-timing-function: linear; + background: $indigo-500; + display: block; + float: right; + height: 100%; + transform-origin: right; + width: 100%; + + @keyframes progress-bar { + 100% { + transform: scaleX(0); + } + } + } + } + + .command-state-failed { + border-left: 2px solid $fail; + background-color: $err-header-background; + color: $err-header-text; + + &:hover { + background: rgba($red-400, 0.3); + } + } + + .command-state-warn { font-style: unset; background-color: $warn-background; - border-left: 2px solid hsl(42, 56%, 53%); + border-left: 2px solid $orange-700; + color: $warn-text; &:hover { background-color: $warn-header-background; } - - .command-wrapper-text .command-method { - color: $warn-text; - } } .command .runnable-err-wrapper { @@ -341,42 +316,7 @@ margin-bottom: 5px; } - .command-with-indicator { - > span > .command-wrapper { - .command-status { - font-weight: 700; - color: #565554; - margin-right: 3px; - } - - .command-body { - color: #565554; - } - - .fa-circle { - padding: 4px; - padding-right: 2px; - display: inline-block; - } - - .fa-circle.successful { - color: $pending; - } - - .fa-circle.aborted { - color: $fail; - } - - .fa-circle.bad { - color: #f0ad4e; - } - - .fa-circle.pending { - color: #aaa; - } - } - } - + // Custom Styles for Specific Commands .command-name-assert { .command-method { span { @@ -389,7 +329,7 @@ } .command-message { - color: #565554; + color: $gray-200; strong { font-weight: 600; @@ -401,52 +341,59 @@ white-space: normal; } - &.command-state-pending { + .command-state-pending { .command-method { + color: $pending; + span { background-color: $pending; - color: white; + color: $black; } } + .command-message { color: $pending; strong { - color: darken($pending, 10%); + color: $indigo-300; } } } - &.command-state-failed { + .command-state-failed { .command-method { + color: $fail; + span { background-color: $fail; - color: white; + color: $black; } } + .command-message { color: $fail; strong { - color: darken($fail, 10%); + color: $red-300; } } } - &.command-state-passed { + .command-state-passed { .command-method { color: $pass; span { background-color: $pass; - color: white; + color: $black; } } + .command-message { - color: darken($pass, 3%); + color: $jade-300; strong { - color: darken($pass, 10%); + color: $jade-200; } } } @@ -469,6 +416,7 @@ } } + // Styles for Uncaught Exception .command-name-uncaught-exception { // need extra spacing between (uncaught exception) and the error message .command-message { @@ -477,13 +425,17 @@ } .command-controls { - i { - padding: 2px; - color: #ababab; + svg { + color: $gray-600; + cursor: pointer; + margin: 0px 2px; + vertical-align: top; } - .studio-command-remove { - display: none; + .command-invisible { + display: inline-block; + margin-left: 5px; + margin-right: 0; } .command-alias, @@ -494,199 +446,109 @@ margin-left: 5px; } - i:hover { - cursor: pointer; - } - label { font-size: 85%; } } - .command-invisible { - display: none; - margin-left: 5px; - margin-right: 0; - } - - .command-is-invisible .command-invisible { - display: inline-block; - } - .command-error { font-style: normal; } - .command-has-num-elements .num-elements { - display: none; - } - - .command-has-num-elements.no-elements .num-elements, - .command-has-num-elements.multiple-elements .num-elements { - display: inline; - } - - .command-has-children > span > .command-wrapper:hover { - .command-expander { - color: #999; - } - } - - .command-has-children.command-has-console-props - > span - > .command-wrapper:hover { - .command-parent-print-btn { - opacity: 1; - pointer-events: unset; - - &:hover { - box-shadow: 0 0 3px #33333370; - background-color: #333333; - } - } - } - - .command-has-children.command-has-console-props > span > .command-wrapper { - position: relative; - .command-parent-print-btn { - opacity: 0; - position: absolute; - top: 0; - right: 0; - pointer-events: none; - transition: all 50ms; - background-color: #333333a0; - padding: 2px 4px; - color: white; - } - } - .command-pin { - color: #999; display: none; flex-shrink: 0; font-size: 14px; line-height: 1; margin-right: 10px; outline: none; - padding: 2px 0 0; + padding: 1px 0 0; text-align: right; width: 15px; - i { - margin-right: 0; + .icon-light { + fill: $gray-800; } } - .command-expander { - color: #bcbccc; - display: none; - text-align: right; - padding-right: 8px; + .command-expander-column { + padding-right: 10px; + padding-left: 5px; width: 25px; - - i { - @extend .#{$fa-css-prefix}-caret-right; - } - } - - .command-has-children > span > .command-wrapper { + .command-expander { - display: block; - } - .command-progress { - visibility: hidden; - } - } + color: $gray-500; + transform: rotate(-90deg); + transition: transform 150ms ease-out; - .command-is-open > span > .command-wrapper { - .command-expander { - i { - @extend .#{$fa-css-prefix}-caret-down; + path { + stroke: $gray-700; } } - .command-alias { - border-radius: 10px !important; + .command-expander-is-open { + transform: rotate(0deg); } } - .command-has-snapshot > span > .command-wrapper { - cursor: pointer; - } - .command-has-console-props > span > .command-wrapper { + .command-has-snapshot:hover, + .command-has-console-props { cursor: pointer; } - .command-has-children > span > .command-wrapper { - .command-number { - display: none; - } - } - - .command-is-pinned > span > .command-wrapper, - .command-has-snapshot > span > .command-wrapper:hover { - .command-number { - display: none; - } - - .command-pin { - display: block; - } - } - - .command { - &.command-is-studio > span > .command-wrapper:hover { - .command-pin { - display: none; - } - .command-number { - display: block; - } - } - } - - .command-state-pending > span > .command-wrapper:hover { - .command-number { - display: block; - } - - .command-pin { - display: none; - } - } - - .command-is-pinned > span > .command-wrapper { - background: lighten($pinned, 40%); + .command-is-pinned { + background: $indigo-1000; border-left: 2px solid $pinned; &, &:hover { - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset; + box-shadow: 0 1px 2px rgba($black, 0.2) inset; } &:hover { - background: lighten($pinned, 38%); + background: $indigo-900; + border-left: 2px solid $pinned; } - .command-wrapper-text { - padding-left: 3px; - - .command-pin { - color: $pinned; + .command-pin { + color: $pinned; + display: block; + + .icon-light { + fill: $purple-700; } } + + .command-pin + .command-number { + display: none + } } + // rendered within ../attempts/attempts.tsx .no-commands { - background-color: #f5f5f5; - border: 1px solid #e3e3e3; + background-color: $gray-1000; + border: 1px solid $gray-900; border-radius: 3px; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba($white, 0.05); min-height: 20px; padding: 9px; } + // additional styles on top of the shared.scss styles + .num-children { + color: $black; + display: inline-block; + background-color: $gray-500; + } + + // additional styles on top of the shared.scss styles + .num-elements { + background-color: $gray-600; + display: inline-block; + color: $black; + vertical-align: text-top; + } + // utilizing element size queries: https://github.com/marcj/css-element-queries // styles take effect when width is greater than or equal to the specified amount &[min-width~="300px"] { @@ -694,31 +556,4 @@ flex-wrap: nowrap; } } - - .studio-prompt { - cursor: auto; - - .command-wrapper { - padding: 5px 10px; - pointer-events: none; - - .command-wrapper-text { - align-items: center; - - .command-message { - .command-message-text { - color: $pending; - } - } - - .command-controls i { - color: $pending; - - &:hover { - color: $pending; - } - } - } - } - } } diff --git a/packages/reporter/src/errors/err-model.ts b/packages/reporter/src/errors/err-model.ts index e511a09ddc..41023b2896 100644 --- a/packages/reporter/src/errors/err-model.ts +++ b/packages/reporter/src/errors/err-model.ts @@ -2,7 +2,7 @@ import _ from 'lodash' import { computed, observable } from 'mobx' -import type { FileDetails } from '@packages/ui-components' +import type { FileDetails } from '@packages/types' export interface ParsedStackMessageLine { message: string diff --git a/packages/reporter/src/errors/error-code-frame.tsx b/packages/reporter/src/errors/error-code-frame.tsx index 1bcbf1c69d..bea4d28cd5 100644 --- a/packages/reporter/src/errors/error-code-frame.tsx +++ b/packages/reporter/src/errors/error-code-frame.tsx @@ -24,7 +24,7 @@ class ErrorCodeFrame extends Component { return (
      - +
                 {frame}
               
      diff --git a/packages/reporter/src/errors/errors.scss b/packages/reporter/src/errors/errors.scss index a7cb97364a..72b826c50d 100644 --- a/packages/reporter/src/errors/errors.scss +++ b/packages/reporter/src/errors/errors.scss @@ -1,20 +1,18 @@ +$code-border-radius: 4px; + .reporter { .error { - background-color: #f5f5f5; + background-color: $gray-1000; min-height: 20px; padding: 24px; h2 { - color: #e94f5f; + color: $err-text; font-size: 1.3em; font-weight: 500; line-height: 1.4; margin-bottom: 0.6em; - > i { - margin-right: 5px; - } - a { float: right; } @@ -25,7 +23,8 @@ } pre { - background: #fcf8e3; + border-color: $orange-300; + color: $orange-300; display: block; width: 100%; white-space: initial; @@ -54,9 +53,9 @@ .runnable-err-wrapper { cursor: default; - margin: 5px 0 5px 5px; + margin: 5px 0 5px 9px; padding-left: 10px; - border-left: 1px dotted #DDD; + border-left: 1px dotted $gray-900; } .studio-err-wrapper { @@ -82,19 +81,19 @@ } .runnable-err-header { + background-color: rgba($red-400, 0.05); display: flex; justify-content: space-between; - background-color: $err-header-background; padding: 5px 10px; font-weight: bold; .runnable-err-name { flex-grow: 2; font-size: 13px; - line-height: 22px;; + line-height: 22px; + color: $err-header-text; - i { - font-size: 10px; + svg { margin-right: 10px; } } @@ -107,24 +106,25 @@ } .runnable-err-message { - padding: 10px; font-family: $monospace; - color: $err-text; font-size: 1em; + padding: 10px; code { - background-color: $err-code-background; - border-radius: 5px; + background-color: rgba($black, 0.2); + border-radius: 4px; + color: $err-code-text; padding: 2px 5px; } strong { - color: $err-text; + color: $err-code-text; font-weight: bold; } } .runnable-err-stack-expander { + border-top: 1px solid rgba($red-400, 0.1); display: flex; .collapsible-header { @@ -134,33 +134,39 @@ outline: 0; div { - background: #fee0e3; + background: $red-900; + } + } + + &:active, + &:hover { + .collapsible-header-text { + color: $red-100; + } + .collapsible-indicator { + .icon-dark { + stroke: $red-200; + } } } div { - background: #ffeaec; cursor: pointer; outline: none; - padding: 7px 5px; + padding: 14px 10px; width: 100%; - &:hover { - background: $err-header-background; - } - - &:active { - background: darken($err-header-background, 2%); - } - .collapsible-header-text { - color: #4f4f4f; - font-size: 13px; + color: $red-300; + font-size: 14px; + font-weight: 500; } .collapsible-indicator { line-height: 18px; - color: #bbbcbd !important; + .icon-dark { + stroke: $red-400; + } } } } @@ -168,38 +174,35 @@ .runnable-err-print { &:focus { outline: none; + } + &:active, + &:hover { div { - background: $err-header-background; + color: $red-100; + } + + svg { + color: $red-200; } } div { - background: #ffeaec; - color: #4f4f4f; + color: $red-300; cursor: pointer; - font-size: 13px; + font-size: 14px; + font-weight: 500; height: 100%; - padding: 7px 10px; + padding: 14px 10px; width: 100%; &:focus { outline: none; } - &:hover { - background: $err-header-background; - } - - &:active { - background: darken($err-header-background, 2%); - } - - i { - border: solid 1px #4f4f4f; - border-radius: 4px; - font-size: 6px; - padding: 4px 3px; + svg { + color: $red-400; + margin: 4px 3px; vertical-align: middle; } @@ -213,7 +216,7 @@ .runnable-err-stack-trace { font-family: $monospace; overflow: auto; - padding: 10px; + padding: 0 10px 10px; .err-stack-line { white-space: pre; @@ -226,29 +229,31 @@ } .test-err-code-frame { - background-color: #fff; - border: 1px solid #ffe4e7; + background-color: $gray-1000; + border: 1px solid rgba($red-400, 0.25); + border-radius: $code-border-radius; margin: 0 10px 10px; .runnable-err-file-path { - &:before { - @extend .#{$fa-css-prefix}; - @extend .#{$fa-css-prefix}-file; - color: #bdbdbd; - margin-right: 5px; - } - - background: #f6f6f6; + background: rgba($gray-900, 0.5); + border-top-left-radius: $code-border-radius; + border-top-right-radius: $code-border-radius; display: block; - font-size: 13px; - line-height: 24px; - padding: 3px 10px; + font-size: 14px; + line-height: 16px; + padding: 8px; word-break: break-all; + + svg { + margin-right: 6px; + vertical-align: middle; + } } pre { - background-color: #fff; border: 0; + border-bottom-left-radius: $code-border-radius; + border-bottom-right-radius: $code-border-radius; padding-left: 10px; } } diff --git a/packages/reporter/src/errors/prism.scss b/packages/reporter/src/errors/prism.scss index 9781032e90..74cbd99d62 100644 --- a/packages/reporter/src/errors/prism.scss +++ b/packages/reporter/src/errors/prism.scss @@ -3,13 +3,14 @@ code[class*="language-"], pre[class*="language-"] { - color: #70787a; + color: $gray-400; margin: 0; + text-shadow: $black 0px 1px; } :not(pre) > code[class*="language-"], pre[class*="language-"] { - background: #fff; + background: $gray-1000; } // .token.comment, @@ -20,7 +21,7 @@ pre[class*="language-"] { // } .token.punctuation { - color: #70787a; + color: $gray-400; } .token.property, @@ -30,7 +31,7 @@ pre[class*="language-"] { .token.constant, .token.symbol, .token.deleted { - color: #c1434f; + color: $red-400; } .token.selector, @@ -39,7 +40,7 @@ pre[class*="language-"] { .token.char, .token.builtin, .token.inserted { - color: #469b76; + color: $jade-400; } .token.operator, @@ -50,7 +51,8 @@ pre[class*="language-"] { .token.regex, .token.important, .token.variable { - color: #e08a45; + color: $orange-400; + background: $gray-1000; } .token.atrule, @@ -58,7 +60,7 @@ pre[class*="language-"] { .token.keyword, .token.function, .token.class-name { - color: #3e76ad; + color: $indigo-400; } .line-numbers .line-numbers-rows { @@ -66,11 +68,11 @@ pre[class*="language-"] { } .line-numbers-rows > span:before { - color: #c4c8cb; + color: $gray-800; } .line-highlight { - background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 100%, hsla(24, 20%, 50%,0)); + background: linear-gradient(to right, rgba($gray-100,.1) 100%, rgba($gray-100,0)); &:before { display: none; diff --git a/packages/reporter/src/errors/test-error.tsx b/packages/reporter/src/errors/test-error.tsx index b83687181f..a4b0d1a809 100644 --- a/packages/reporter/src/errors/test-error.tsx +++ b/packages/reporter/src/errors/test-error.tsx @@ -13,6 +13,9 @@ import { onEnterOrSpace } from '../lib/util' import Attempt from '../attempts/attempt-model' import Command from '../commands/command-model' +import WarningIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/warning_x8.svg' +import TerminalIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/technology-terminal_x16.svg' + interface DocsUrlProps { url: string | string[] } @@ -65,7 +68,7 @@ const TestError = observer((props: TestErrorProps) => {
      - + {err.name}
      @@ -86,7 +89,7 @@ const TestError = observer((props: TestErrorProps) => { role='button' tabIndex={0} > -
      Print to console
      +
      Print to console
      } diff --git a/packages/reporter/src/header/controls.tsx b/packages/reporter/src/header/controls.tsx index 9de5afaca7..04bbabedbb 100755 --- a/packages/reporter/src/header/controls.tsx +++ b/packages/reporter/src/header/controls.tsx @@ -8,6 +8,13 @@ import Tooltip from '@cypress/react-tooltip' import defaultEvents, { Events } from '../lib/events' import { AppState } from '../lib/app-state' +import ChevronDownIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/chevron-down-small_x16.svg' +import ChevronUpIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/chevron-up-small_x16.svg' +import NextIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-next_x16.svg' +import PlayIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-play_x16.svg' +import RestartIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-restart_x16.svg' +import StopIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-stop_x16.svg' + const ifThen = (condition: boolean, component: React.ReactNode) => ( condition ? component : null ) @@ -19,55 +26,55 @@ interface Props { const Controls = observer(({ events = defaultEvents, appState }: Props) => { const emit = (event: string) => () => events.emit(event) - const toggleAutoScrolling = () => { - appState.toggleAutoScrolling() + const togglePreferencesMenu = () => { + appState.togglePreferencesMenu() events.emit('save:state') } return (
      - {ifThen(appState.isPaused, ( - - - - ))} + Open Testing Preferences

      } className='cy-tooltip'> + +
      {ifThen(appState.isPaused, ( Resume C

      } className='cy-tooltip'> -
      - ))} - {ifThen(!appState.isPaused, ( - {appState.autoScrollingEnabled ? 'Disable' : 'Enable'} Auto-scrolling A

      } className='cy-tooltip'> -
      ))} {ifThen(appState.isRunning && !appState.isPaused, ( Stop Running S

      } className='cy-tooltip' visible={appState.studioActive ? false : null}>
      ))} {ifThen(!appState.isRunning, ( Run All Tests R

      } className='cy-tooltip'>
      ))} {ifThen(!!appState.nextCommandName, ( Next [N]:{appState.nextCommandName}

      } className='cy-tooltip'>
      ))} diff --git a/packages/reporter/src/header/header.scss b/packages/reporter/src/header/header.scss index 5da6053599..8e79f400ad 100644 --- a/packages/reporter/src/header/header.scss +++ b/packages/reporter/src/header/header.scss @@ -1,13 +1,17 @@ +$color-transition: color 150ms ease-out; + .reporter { header { - background-color: #f8f8f8; - border-bottom: 1px solid #ddd; + background-color: $gray-1000; display: flex; flex-shrink: 0; flex-wrap: wrap; + gap: 8px; + font-family: $font-system; min-height: $header-height; outline: 0; overflow: hidden; + padding: 20px 16px; width: 100%; z-index: 1; @@ -16,22 +20,18 @@ } button { - background-color: #f8f8f8; + background-color: transparent; border-color: transparent; border-radius: 0; - display: block; + display: inline-block; + font-weight: 300; line-height: 26px; outline: 0; - padding: 10px 0; + padding: 0 8px; text-align: center; - width: 40px; &:hover { - background-color: #e9e9e9; - } - - &:active { - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + background-color: $gray-900; } &[disabled], @@ -39,141 +39,121 @@ &[disabled]:active { background: none; box-shadow: none; - color: #999; + color: $gray-500; } } } - .focus-tests { + .toggle-specs-wrapper { display: flex; + height: 24px; button { - border-right: 1px solid #ddd; - font-weight: 400; - padding: 10px 12px; + color: $gray-700; + font-size: 16px; + font-weight: 300; + padding-left: 0; + padding-right: 8px; + transition: $color-transition; width: auto !important; - span { - display: none; + &:focus, + &:hover { + background-color: initial; + + svg { + color: $gray-400; + transition: $color-transition; + } + + .toggle-specs-text { + color: $gray-600; + transition: $color-transition; + } } - i { - margin-right: 5px; + .toggle-specs-text { + transition: $color-transition; + } + + svg { + margin-right: 8px; + margin-bottom: -2px; } } } .stats { + align-items: center; + border: 1px solid $gray-900; + border-radius: 4px; display: flex; flex-wrap: wrap; - margin-bottom: 0; - padding: 0; + height: 24px; + justify-content: space-between; + padding: 0 4px; + width: 124px; li { - display: block; - font-size: 16px; - height: 46px; - line-height: 26px; - list-style-type: none; - padding: 10px 5px; - - &.passed { - color: #23AE89; - } - - &.failed { - color: #E94B3B; - } - - &.pending { - color: #aaa; - } - - i { - margin: 5px; - } - } - - .duration { - border-left: 1px solid #ddd; - border-right: 1px solid #ddd; - padding-left: 10px; - padding-right: 10px; - } - } - - .controls { - display: flex; - flex-wrap: wrap; - - > span { display: flex; + font-size: 12px; + font-weight: 600; + list-style-type: none; + padding: 0 4px; - &:last-child button { - border-right: 1px solid #ddd; - } - } - - .paused-label { - align-items: center; - margin-right: 5px; - - label { - background-color: #CC4239; - } - } - - i { - font-size: 90%; - margin: 5px; - - &.fa-redo { - font-size: 100%; - position: relative; - top: 1px; - } - } - - .toggle-auto-scrolling { - line-height: 25px; - - i { - font-size: 100%; + svg { + margin-right: 2px; } - i:first-child { - @extend .far; - @extend .#{$fa-css-prefix}-circle; - color: #999; - font-size: 80%; - margin-right: 3px; - position: relative; - top: -1px; - } + .num { + color: $white; + line-height: 12px; + vertical-align: text-top; + width: 16px; + display: inline-block; + text-align: center; - &.auto-scrolling-enabled { - i:first-child { - @extend .fas; - @extend .#{$fa-css-prefix}-circle; - color: $yellow-dark; + &.empty { + color: $gray-800; } } } } - // utilizing element size queries: https://github.com/marcj/css-element-queries - // styles take effect when width is greater than or equal to the specified amount - &[min-width~="398px"] { - header button { - width: 50px; + .controls { + align-items: center; + border: 1px solid $gray-900; + border-radius: 4px; + display: flex; + flex-wrap: wrap; + justify-content: center; + height: 24px; + + .testing-preferences-toggle { + border-left: none; + color: $gray-700; + margin-left: 0; + + &.open { + background-color: $gray-900; + color: $white; + } } - .focus-tests button span { - display: inline; - } + span { + height: 100%; - .stats li { - padding: 10px; + button { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: $gray-400; + width: 31px; + padding: 0px; + border-left: 1px solid $gray-900; + margin-left: -1px; + } } } } diff --git a/packages/reporter/src/header/header.tsx b/packages/reporter/src/header/header.tsx index 3d97ca6e1e..70c8527d76 100644 --- a/packages/reporter/src/header/header.tsx +++ b/packages/reporter/src/header/header.tsx @@ -3,8 +3,11 @@ import React from 'react' // @ts-ignore import Tooltip from '@cypress/react-tooltip' +import MenuExpandRightIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/menu-expand-right_x16.svg' + import defaultEvents, { Events } from '../lib/events' import { AppState } from '../lib/app-state' +import { action } from 'mobx' import Controls from './controls' import Stats from './stats' @@ -18,14 +21,24 @@ export interface ReporterHeaderProps { const Header = observer(({ appState, events = defaultEvents, statsStore }: ReporterHeaderProps) => (
      - View All Tests F

      } wrapperClassName='focus-tests' className='cy-tooltip'> -
      -
      +
      )) diff --git a/packages/reporter/src/header/stats.tsx b/packages/reporter/src/header/stats.tsx index e224c8f8ef..4f339692ad 100644 --- a/packages/reporter/src/header/stats.tsx +++ b/packages/reporter/src/header/stats.tsx @@ -1,10 +1,14 @@ +import cs from 'classnames' import { observer } from 'mobx-react' import React from 'react' import { StatsStore } from './stats-store' +import FailedIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/status-failed_x12.svg' +import PassedIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/status-passed_x12.svg' +import PendingIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/status-pending_x12.svg' + const count = (num: number) => num > 0 ? num : '--' -const formatDuration = (duration: number) => duration ? String((duration / 1000).toFixed(2)).padStart(5, '0') : '--' interface Props { stats: StatsStore @@ -13,22 +17,19 @@ interface Props { const Stats = observer(({ stats }: Props) => (
      • -
TypeTypeFunction Alias(es) # Calls
cell