diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 53a684aa..00000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-version: 2
-jobs:
- build:
- docker:
- # https://circleci.com/docs/2.0/docker-image-tags.json
- - image: circleci/node:current
- steps:
- - checkout
- - restore_cache:
- name: Restore Yarn Package Cache
- keys:
- - yarn-packages-{{ checksum "yarn.lock" }}
- - run:
- name: Install Packages
- command: yarn install
- - save_cache:
- name: Save Yarn Package Cache
- key: yarn-packages-{{ checksum "yarn.lock" }}
- paths:
- - ~/.cache/yarn
- - run:
- name: Check Formatting
- command: yarn prettier:ci
- - run:
- name: Test
- command: yarn test
diff --git a/.editorconfig b/.editorconfig
index cc7df4af..b07f17bc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,6 +9,9 @@ indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
+[*.{js,ts}]
+quote_type = single
+
[*.md]
indent_size = 4
insert_final_newline = false
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 39122d17..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": ["@cartant/eslint-config"],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "ecmaVersion": 2019,
- "project": "tsconfig.json",
- "sourceType": "module"
- },
- "root": true,
- "rules": {
- "sort-keys": ["off"]
- }
-}
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 86535ca0..00000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: [cartant] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..4c1c32f1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,33 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: weekly
+
+ - package-ecosystem: npm
+ directory: "/"
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 10
+ allow:
+ - dependency-type: development
+ ignore:
+ - dependency-name: "@types/node"
+ update-types:
+ - version-update:semver-major
+ - version-update:semver-minor
+ versioning-strategy: increase
+ groups:
+ vitest:
+ patterns:
+ - "vitest"
+ - "@vitest/*"
+ typescript-eslint:
+ patterns:
+ - "typescript-eslint"
+ - "@typescript-eslint/*"
+ eslint:
+ patterns:
+ - "eslint"
+ - "@eslint/*"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..c5df2ff6
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,57 @@
+on:
+ push:
+ branches:
+ - main
+ pull_request: {}
+ workflow_call: {}
+
+concurrency:
+ group: '${{ github.workflow }} - ${{ github.head_ref || github.ref }}'
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+
+ check:
+ strategy:
+ matrix:
+ node-version: [18, 20]
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Setup LCOV
+ uses: hrishikesh-kadam/setup-lcov@v1
+ - name: Setup Yarn
+ run: corepack enable
+
+ - name: Install Packages
+ run: yarn install
+
+ - name: Type Check
+ run: yarn typecheck
+
+ - name: Lint
+ run: yarn lint
+
+ - name: Test Coverage
+ run: yarn coverage
+
+ - name: Report Coverage
+ if: ${{ matrix.node-version == 20 && github.event_name == 'pull_request' }}
+ uses: zgosalvez/github-actions-report-lcov@v4
+ with:
+ coverage-files: coverage/lcov.info
+ minimum-coverage: 90
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ update-comment: true
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 00000000..1a3b4037
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,45 @@
+on:
+ workflow_dispatch: {}
+ release:
+ types:
+ - published
+
+jobs:
+ check:
+ uses: ./.github/workflows/ci.yml
+ secrets: inherit
+
+ publish:
+ needs: check
+
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ id-token: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: lts/*
+ registry-url: 'https://registry.npmjs.com'
+ check-latest: true
+ - name: Setup Yarn
+ run: corepack enable
+
+ - name: Install Packages
+ run: yarn install
+
+ - name: Build
+ run: yarn build
+
+ - name: Publish
+ run: |
+ npm install -g npm@latest
+ npm publish --provenance
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 248d183b..81021989 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,133 @@
-yarn-error.log
-/build
-/dist
-/node_modules
-/temp
+# Node.gitignore
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+.cache
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
diff --git a/.husky/pre-commit b/.husky/pre-commit
deleted file mode 100644
index d2ae35e8..00000000
--- a/.husky/pre-commit
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
-
-yarn lint-staged
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 00000000..ea03a753
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,6 @@
+{
+ "line-length": false,
+ "MD024": {
+ "siblings_only": true
+ }
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index bc37f281..425232b4 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -4,22 +4,5 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
- {
- "type": "node",
- "request": "launch",
- "name": "mocha",
- "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
- "args": [
- "-r",
- "ts-node/register",
- "--timeout",
- "999999",
- "--colors",
- "${workspaceFolder}/tests/rules/*.ts",
- ],
- "console": "integratedTerminal",
- "internalConsoleOptions": "neverOpen",
- "protocol": "inspector"
- }
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 00ad71fb..dde28ebb 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,6 @@
{
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit"
+ },
"typescript.tsdk": "node_modules\\typescript\\lib"
-}
\ No newline at end of file
+}
diff --git a/.yarnrc.yml b/.yarnrc.yml
new file mode 100644
index 00000000..3186f3f0
--- /dev/null
+++ b/.yarnrc.yml
@@ -0,0 +1 @@
+nodeLinker: node-modules
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 264d1561..069e2193 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,278 +1,144 @@
-
-## [5.0.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v5.0.2...v5.0.3) (2023-03-28)
+# Changelog
-## Fixes
+[npm history](https://www.npmjs.com/package/eslint-plugin-rxjs-x?activeTab=versions)
-- Widen the TypeScript peer dependency. ([e9ed8b3](https://github.com/cartant/eslint-plugin-rxjs/commit/e9ed8b3))
+## v0.5.1 (2024-12-03)
-
-## [5.0.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v5.0.1...v5.0.2) (2022-01-26)
+### Features
-## Fixes
+- **no-misused-observables**: new rule similar to `@typescript-eslint/no-misused-promises`. ([#58](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/58)) ([41c7be8](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/41c7be8976b3941b4a9f3e9bb4aa6105978509b6))
+- add `name` to each configuration. ([#75](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/75)) ([c3b3b33](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/c3b3b33e42235936ad2b6e49231c579088acc52c))
-- Don't ignore `$`-suffixed properties in the `suffix-subjects` rule. ([d4a94c0](https://github.com/cartant/eslint-plugin-rxjs/commit/d4a94c0))
+## v0.5.0 (2024-11-28)
-
-## [5.0.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v5.0.0...v5.0.1) (2022-01-12)
+### Breaking Changes
-## Fixes
+- **no-ignored-observable**: rule removed. Use `no-floating-observables` instead. ([#55](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/55)) ([1268dc8](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/1268dc86741a37a71d5b1994b8702a8c3874db4d))
-- The `no-ignored-takewhile-value` rule is now aware of array and object destructuring patterns. ([f0f0cf3](https://github.com/cartant/eslint-plugin-rxjs/commit/f0f0cf3))
+### Features
-
-## [5.0.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v4.0.4...v5.0.0) (2022-01-06)
+- **no-floating-observables**: new rule which re-implements `no-ignored-observable`. Adds `ignoreVoid` option which defaults to `true`. ([#55](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/55)) ([1268dc8](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/1268dc86741a37a71d5b1994b8702a8c3874db4d))
+- **recommended configuration**: enabled `no-topromise`, `prefer-observer`, `prefer-root-operators`, and `throw-error`. ([#56](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/56)) ([ada5d55](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/ada5d55ef29aa07ece11a72a0322dc58c686498a))
-## Breaking Changes
+## v0.4.1 (2024-11-26)
-- The `prefer-observer` rule now has a fixer. ([d40b0a0](https://github.com/cartant/eslint-plugin-rxjs/commit/d40b0a0))
+No updates!
-
-## [4.0.4](https://github.com/cartant/eslint-plugin-rxjs/compare/v4.0.3...v4.0.4) (2021-12-31)
+## v0.4.0 (2024-11-24)
-## Fixes
+### Breaking Changes
-- The `alias` option of the `no-unsafe-takeuntil` rule now supports method calls. See [this PR](https://github.com/cartant/eslint-plugin-rxjs/pull/90). ([4fe7423](https://github.com/cartant/eslint-plugin-rxjs/commit/4fe7423))
+- **no-implicit-any-catch**: default to allow explicit `any` ([#42](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/42)) ([93ef8e8](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/93ef8e8c7a0d3d93142e901dabb17db78a84a2cd))
-
-## [4.0.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v4.0.2...v4.0.3) (2021-11-19)
+### Features
-## Fixes
+- add a strict configuration: ([#41](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/41)) ([f2bf3fa](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/f2bf3fadcbe72dfec5c69db8ec683dc2b7a62a2a))
-- Escape `RegExp` characters in the `suffix-subjects` rule's `suffix` option. See [this issue](https://github.com/cartant/eslint-plugin-rxjs/issues/88). ([a23a69c](https://github.com/cartant/eslint-plugin-rxjs/commit/a23a69c))
-- Don't effect failures for inner `first`-like operators in the `no-unsafe-first` rule. See [this issue](https://github.com/cartant/eslint-plugin-rxjs/issues/89). ([19806a4](https://github.com/cartant/eslint-plugin-rxjs/commit/19806a4))
+## v0.3.2 (2024-11-21)
-
-## [4.0.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v4.0.1...v4.0.2) (2021-11-08)
+### Features
-## Fixes
+- **prefer-root-operators**: new rule for migrating from `rxjs/operators` to `rxjs` ([#34](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/34)) ([e3b8090](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/e3b8090a6f2ad346ddeaedb9f5d46543c497f323))
+- **no-topromise**: suggest `lastValueFrom` or `firstValueFrom` ([#38](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/38)) ([cec2d60](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/cec2d604931a2862aff38a3d4354dea8a7b66ada))
-- Don't effect failures in the `throw-error` rule when `unknown` is thrown. See [this issue](https://github.com/cartant/eslint-plugin-etc/issues/39). ([784f463](https://github.com/cartant/eslint-plugin-rxjs/commit/784f463))
+### Chores
-
-## [4.0.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v4.0.0...v4.0.1) (2021-10-26)
+- **no-compat**: deprecated ([#32](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/32)) ([05862a3](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/05862a334ea6e7139fa8f809a6da0c008d4af2e6))
-## Features
+## v0.3.1 (2024-11-16)
-* Add `no-subscribe-handlers` rule. ([ea36a6d](https://github.com/cartant/eslint-plugin-rxjs/commit/ea36a6d))
+### Bug Fixes
-
-## [4.0.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.7...v4.0.0) (2021-10-17)
+- **no-ignored-error**: fix observer objects not getting checked for `error` property ([#27](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/27)) ([46e105f](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/46e105fde371a2013713f5e141b2c67ab039bd07))
-## Breaking Changes
+## v0.3.0 (2024-11-15)
-* Support `eslint` v8 and `@typescript-eslint` v5. ([644953a](https://github.com/cartant/eslint-plugin-rxjs/commit/644953a))
+### Breaking Changes
-
-## [3.3.7](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.6...v3.3.7) (2021-08-29)
+- **ban-operators**: improve type checking of banned operators, report error at usage instead of in import statement ([#25](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/25)) ([994ff25](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/994ff25391cc4efbb2f2cfa99c323c7280e9d1b5))
+- **throw-error**: stop linting regular `throw` statements ([#22](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/22)) ([02fdffd](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/02fdffde6b9376621b902d2ebbae4fb8080d29f1))
-## Fixes
+### Features
-* Allow multiple `takeUntil` operators with other operators placed in between. ([e66478c](https://github.com/cartant/eslint-plugin-rxjs/commit/e66478c))
+- **no-ignored-default-value**: new rule for enforcing `defaultValue` ([#15](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/15)) ([9bd896e](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/9bd896e0acb87cce2931ecda8b683fb5e9a8837c))
-
-## [3.3.6](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.5...v3.3.6) (2021-08-14)
+## v0.2.4 (2024-11-09)
-## Fixes
+### Features
-* Don't attempt to ban shallow/root operator imports - introduced in RxJS 7.2 - in the `ban-operators`. ([489a72e](https://github.com/cartant/eslint-plugin-rxjs/commit/489a72e))
+- **macro**: deprecated ([#13](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/13)) ([39be258](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/39be258ad359bd1e79f057302d7ffe12954f9c14))
-
-## [3.3.5](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.4...v3.3.5) (2021-07-09)
+## v0.2.3 (2024-11-08)
-## Fixes
+### Bug Fixes
-* Support shallow/root operator imports - introduced in RxJS 7.2 - in the `ban-operators` and `no-tap` rules. ([009381f](https://github.com/cartant/eslint-plugin-rxjs/commit/009381f))
+- **no-ignored-replay-buffer**: check config bufferSize ([#12](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/12)) ([ef2f886](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/ef2f8866684ed6f918eb8c465e90a1de8982186a))
-
-## [3.3.4](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.3...v3.3.4) (2021-06-26)
+### Chores
-## Fixes
+- change `rxjs` to an optional peer dependency ([90b03e6](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/90b03e6a01e0357603eb6426638ca43e0f392dca))
-* Check for non-RxJS `takeWhile` imports in `no-ignored-takewhile-value`. ([476fc29](https://github.com/cartant/eslint-plugin-rxjs/commit/476fc29))
+## v0.2.2 (2024-11-07)
-
-## [3.3.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.2...v3.3.3) (2021-05-29)
+### Breaking Changes
-## Fixes
+- TypeScript >=4.7.4 is required
-* Bump `eslint-etc` version. ([ca61caa](https://github.com/cartant/eslint-plugin-rxjs/commit/ca61caa))
+### Bug Fixes
-
-## [3.3.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.1...v3.3.2) (2021-05-28)
+- fix broken imports in ESM configs using TypeScript versions lower than 5.5 ([#11](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/11)) ([1693df0](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/1693df0423acb1eb7cef237620ed31d2ee5520fa))
-## Fixes
+## v0.2.1 (2024-11-07)
-* Support factories in the `throw-error` rule. ([f4e8835](https://github.com/cartant/eslint-plugin-rxjs/commit/f4e8835))
+### Chores
-
-## [3.3.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.3.0...v3.3.1) (2021-05-19)
+- decrease minimum `typescript-eslint` version to ^8.1.0 ([#10](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/10)) ([e7d0d70](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/e7d0d7078b50d1ef72c48318159a80ce481ef73c))
-## Changes
+## v0.2.0 (2024-11-05)
-* Remove the `no-subject-value` rule from recommended configuration. This was an oversight. Personally, I use the rule, but it's probably too opinionated to be in the recommended configuration. ([79b7bc0](https://github.com/cartant/eslint-plugin-rxjs/commit/79b7bc0))
+### Breaking Changes
-
-## [3.3.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.2.0...v3.3.0) (2021-05-01)
+- improve CommonJS typing to avoid needing `.default` ([#4](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/4)) ([0b47390](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/0b473900c141403a1eb45e5a44fd2f2b43ebb6d5))
-## Features
+### Documentation
-* The `no-internal` rule now has a fixer. ([dc480b2](https://github.com/cartant/eslint-plugin-rxjs/commit/dc480b2))
+- add options documentation to rule docs ([#6](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/6)) ([ee705d2](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/ee705d23efe7c779bfabb855e82130c664ba35c4))
-
-## [3.2.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.5...v3.2.0) (2021-04-25)
+## v0.1.0 (2024-11-04)
-## Features
+### Breaking Changes
-* The `no-ignored-subscribe` and `no-nested-subscribe` rules now support types that implement `Subscribable`. ([57f6e3f](https://github.com/cartant/eslint-plugin-rxjs/commit/57f6e3f))
+- TypeScript >=4.2.0 is required
+- `tslib` ^2.1.0 is required
-
-## [3.1.5](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.4...v3.1.5) (2021-04-08)
+### Chores
-## Fixes
+- drop dependencies `tsutils` and `tsutils-etc`, add dependency `ts-api-utils` ([#3](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/3)) ([c64f9f6](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/c64f9f6bd810f7d114c9dac9f6ab72df1b2d2e31))
-* Match only `subscribe` calls that are nested in arguments. ([0dc28aa](https://github.com/cartant/eslint-plugin-rxjs/commit/0dc28aa))
+## v0.0.2 (2024-11-01)
-
-## [3.1.4](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.3...v3.1.4) (2021-04-05)
+### Bug Fixes
-## Fixes
+- fix wrong types for CommonJS ([#2](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/pull/2)) ([2d330aa](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/commit/2d330aa943f31bbb7831607c0573b9c8e41d8268))
-* Allow `takeUntil` after `takeUntil`. ([d1a2549](https://github.com/cartant/eslint-plugin-rxjs/commit/d1a2549))
+## v0.0.1 (2024-11-01)
-
-## [3.1.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.2...v3.1.3) (2021-03-22)
+Initial prerelease version.
-## Fixes
+### Breaking Changes
-* Set minimum `eslint-etc` version. ([4fae336](https://github.com/cartant/eslint-plugin-rxjs/commit/4fae336))
+- `eslint` ^8.57.0 || 9.0.0 is required
+- `typescript-eslint` ^8 is required
+- Node.js ^18.18.0 || ^20.9.0 || >= 21.1.0 is required
-
-## [3.1.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.1...v3.1.2) (2021-03-20)
+### Bug Fixes
-## Fixes
+- **no-implicit-any-catch**: fix `typeAnnotation` bug breaking linting.
-* Enable TypeScript's `strict` option and fix related problems. ([2bea9e0](https://github.com/cartant/eslint-plugin-rxjs/commit/2bea9e0))
+### Chores
-
-## [3.1.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.1.0...v3.1.1) (2021-02-14)
-
-## Changes
-
-* Improve `no-unsafe-takeuntil` docs and fix failure message grammar. ([e3e8fed](https://github.com/cartant/eslint-plugin-rxjs/commit/e3e8fed))
-
-
-## [3.1.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.0.1...v3.1.0) (2021-02-13)
-
-## Features
-
-* Added a `strict` option to the `finnish` rule. ([8bf0d1d](https://github.com/cartant/eslint-plugin-rxjs/commit/8bf0d1d))
-
-
-## [3.0.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v3.0.0...v3.0.1) (2021-02-03)
-
-## Fixes
-
-* Support arrow functions without parameter parentheses in `no-implicit-any-catch`. ([37427ad](https://github.com/cartant/eslint-plugin-rxjs/commit/37427ad))
-
-
-## [3.0.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.7...v3.0.0) (2021-01-30)
-
-## Breaking Changes
-
-* Check for an `Observable` type in `no-implicit-any-catch` - a breaking change because the previous version of this rule didn't require type information. ([ebfb553](https://github.com/cartant/eslint-plugin-rxjs/commit/ebfb553))
-
-## Fixes
-
-* Check for an `Observable` type in `prefer-observer`. ([30012be](https://github.com/cartant/eslint-plugin-rxjs/commit/30012be))
-
-
-## [2.1.7](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.6...v2.1.7) (2021-01-19)
-
-## Fixes
-
-* Don't insist on type references when checking for obserables. ([521fe55](https://github.com/cartant/eslint-plugin-rxjs/commit/521fe55))
-
-
-## [2.1.6](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.5...v2.1.6) (2021-01-11)
-
-## Changes
-
-* Fix GitHub URL for docs. ([a238c2d](https://github.com/cartant/eslint-plugin-rxjs/commit/a238c2d))
-
-
-## [2.1.5](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.4...v2.1.5) (2020-11-28)
-
-## Changes
-
-* Use `files` in `package.json` instead of `.npmignore`. ([99cb9ec](https://github.com/cartant/eslint-plugin-rxjs/commit/99cb9ec))
-
-
-## [2.1.4](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.3...v2.1.4) (2020-11-21)
-
-## Fixes
-
-* Fixed a problem with `no-cyclic-action` when used with effects/epics that return `Observable`. ([79b9e82](https://github.com/cartant/eslint-plugin-rxjs/commit/79b9e82))
-
-
-## [2.1.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.2...v2.1.3) (2020-11-05)
-
-## Fixes
-
-* `no-ignored-subscription` should not effect failures for `Subscriber` instances passed to `subscribe`. ([72e11ec](https://github.com/cartant/eslint-plugin-rxjs/commit/72e11ec))
-
-
-## [2.1.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.1...v2.1.2) (2020-11-03)
-
-## Changes
-
-* Use the public TypeScript API (`getTypeArguments`) to obtain the type arguments in the `no-cyclic-action` rule. ([7f55bcb](https://github.com/cartant/eslint-plugin-rxjs/commit/7f55bcb))
-
-
-## [2.1.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.1.0...v2.1.1) (2020-11-03)
-
-## Changes
-
-* Use the public TypeScript API (`getTypeOfSymbolAtLocation`) to obtain the action type in the `no-cyclic-action` rule. ([56687db](https://github.com/cartant/eslint-plugin-rxjs/commit/56687db))
-
-
-## [2.1.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.0.1...v2.1.0) (2020-11-03)
-
-## Changes
-
-* Added the `no-cyclic-action` rule for effects and epics. ([5e03092](https://github.com/cartant/eslint-plugin-rxjs/commit/5e03092))
-
-
-## [2.0.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v2.0.0...v2.0.1) (2020-11-03)
-
-## Changes
-
-* Update rule metadata.
-
-
-## [2.0.0](https://github.com/cartant/eslint-plugin-rxjs/compare/v1.0.3...v2.0.0) (2020-10-29)
-
-## Breaking Changes
-
-* `no-implicit-any-catch` is now enforced for error callbacks - and error methods on observers - passed to `subscribe` and `tap`, too. ([1b9234b](https://github.com/cartant/eslint-plugin-rxjs/commit/1b9234b))
-
-
-## [1.0.3](https://github.com/cartant/eslint-plugin-rxjs/compare/v1.0.2...v1.0.3) (2020-10-27)
-
-## Changes
-
-* Specify Node 10 as the minimum `engines` in `package.json` and downlevel to ES2018.
-
-
-## [1.0.2](https://github.com/cartant/eslint-plugin-rxjs/compare/v1.0.1...v1.0.2) (2020-10-25)
-
-## Changes
-
-* Deprecate `no-tap` in favour of `ban-operators`. `no-do`/`no-tap` was an early TSLint rule and `ban-operators` is the preferred rule for banning operators as it allows a message to be specified.
-
-
-## [1.0.1](https://github.com/cartant/eslint-plugin-rxjs/compare/v1.0.0...v1.0.1) (2020-10-23)
-
-## Changes
-
-* Specify `engines` in `package.json`.
-* Downlevel the TypeScript output to ES2019.
\ No newline at end of file
+- drop dependency `eslint-etc`
+- drop dependency `requireindex`
+- add `rxjs` >=7 as peer dependency
+- add `requiresTypeChecking` to `meta.docs` of relevant rules
+- switch from mocha to vitest
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8c95e7b7..f607efed 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1 +1,108 @@
-There's nothing here, yet. Thanks for looking. I'll eventually get around to filling this out.
\ No newline at end of file
+# Contributing
+
+## Issues
+
+To submit a bug or feature request, please first:
+
+1. Use the latest version of this plugin.
+2. Search existing issues, including closed issues, for your issue.
+ - Since this plugin is a fork, please search the previous repositories too: `cartant/eslint-plugin-rxjs` and `cartant/rxjs-tslint-rules`.
+ - Even if your issue is different, please feel free to link to related issues for context. It really helps!
+
+## Getting Started
+
+To start working an issue, first fork this repository.
+
+Then install Yarn with corepack (included in all modern versions of Node.js):
+
+```sh
+corepack enable
+```
+
+Then run `yarn` in this repository to restore packages.
+
+## Working
+
+### Building
+
+Run `yarn build` to build this plugin into the `dist` folder.
+
+### Linting
+
+Use `yarn lint` to run all linters (ESLint, markdownlint, and eslint-doc-generator).
+If the eslint-doc-generator lint step fails,
+you may need to run `yarn docs` to auto-update the rule documentation based on your changes.
+
+All linting must pass for a pull request to be accepted.
+We recommend you use the VS Code plugins for ESLint and markdownlint during development.
+
+### Testing
+
+Use `yarn test` to run the tests in watch mode.
+We use [vitest](https://vitest.dev) for unit testing.
+
+All unit tests must pass for a pull request to be accepted.
+We also enforce code coverage, which you can check with `yarn coverage --coverage.reporter text`.
+
+## Pull Request
+
+For major changes, before submitting a PR, please submit an Issue so the change can be discussed first.
+
+This repository uses conventional commits.
+Essentially this means the title of your PR should be formatted like this:
+
+```text
+():
+```
+
+If the PR involves a breaking changes, put an exclamation mark before the colon.
+The body of the PR should start with "BREAKING CHANGE:" and describe the change clearly.
+
+The `` may be a specific rule name, config name, or a more broad category.
+
+### Examples
+
+```text
+feat(prefer-root-operators): new rule for banning `rxjs/operators`
+```
+
+```text
+fix(no-ignored-error): check observer object too, not just callbacks
+```
+
+```text
+docs(no-async-subscribe): additional reasoning behind this rule
+```
+
+```text
+chore(deps-dev): bump @eslint/plugin-kit from 0.2.2 to 0.2.3
+```
+
+```text
+feat(throw-error)!: stop linting throw statements
+
+BREAKING CHANGE: regular JavaScript `throw` statements will no longer be handled by this rule.
+```
+
+### Types
+
+- `feat`: new functionality
+- `fix`: bug fixes
+- `docs`: only documentation changes
+- `test`: only unit test changes
+- `chore`: any other changes (e.g. CI/CD, dependencies, repo maintenance)
+
+You may also see `refactor` and `style` in this repository.
+
+### Reviews
+
+After submitting a PR, your PR will be reviewed by the code owners of this repository.
+Please work with us to address any feedback, which may include but is not limited to:
+
+- Functional changes
+- Test coverage
+- Splitting PR into separate requests
+- Small amounts of bike-shedding
+
+Address each requested change and/or respond using line comments, then re-request a review.
+Once your PR is approved, we will merge it and publish the change in a reasonable amount of time.
diff --git a/LICENSE b/LICENSE
index efe8fbf6..d25db685 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019 Nicholas Jamieson and contributors
+Copyright (c) 2019 Nicholas Jamieson and contributors, 2024-PRESENT Jason Weinzierl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index de4bd10e..56b8cbc3 100644
--- a/README.md
+++ b/README.md
@@ -1,116 +1,125 @@
-# eslint-plugin-rxjs
+# eslint-plugin-rxjs-x
-[](https://github.com/cartant/eslint-plugin-rxjs/blob/master/LICENSE)
-[](https://www.npmjs.com/package/eslint-plugin-rxjs)
-[](https://npmjs.org/package/eslint-plugin-rxjs)
-[](https://app.circleci.com/pipelines/github/cartant)
-[](https://david-dm.org/cartant/eslint-plugin-rxjs)
-[](https://david-dm.org/cartant/eslint-plugin-rxjs#info=devDependencies)
-[](https://david-dm.org/cartant/eslint-plugin-rxjs#info=peerDependencies)
+[](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/blob/master/LICENSE)
+[](https://www.npmjs.com/package/eslint-plugin-rxjs-x)
-This package contains a bunch of ESLint rules for RxJS. Essentially, it's a re-implementation of the rules that are in the [`rxjs-tslint-rules`](https://github.com/cartant/rxjs-tslint-rules) package. (The Angular-specific rules in `rxjs-tslint-rules` have been re-implemented in [`eslint-plugin-rxjs-angular`](https://github.com/cartant/eslint-plugin-rxjs-angular).)
+This ESLint plugin is intended to prevent issues with [RxJS](https://github.com/ReactiveX/rxjs).
-Some of the rules are rather opinionated and are not included in the `recommended` configuration. Developers can decide for themselves whether they want to enable opinionated rules.
+Most of these rules require TypeScript typed linting and are indicated as such below.
-Almost all of these rules require the TypeScript parser for ESLint.
+## Migrating from `eslint-plugin-rxjs`
-# Install
+This project is a fork of [`eslint-plugin-rxjs`](https://github.com/cartant/eslint-plugin-rxjs)
+initially started to support the new ESLint flat config format.
+There are some breaking changes:
-Install the ESLint TypeScript parser using npm:
+- The old `.eslintrc` format is not supported.
+ - If you need to continue using this old format, use the original `eslint-plugin-rxjs` or a different fork.
+- The plugin namespace specified in the `recommended` config was changed from `rxjs` to `rxjs-x`.
+ - e.g. In your ESLint config, `rxjs/no-subject-value` should be renamed to `rxjs-x/no-subject-value`.
+- The rule `rxjs/no-ignored-observable` is renamed to `rxjs-x/no-floating-observables`.
-```
-npm install @typescript-eslint/parser --save-dev
-```
+A complete description of all changes are documented in the [CHANGELOG](CHANGELOG.md) file.
-Install the package using npm:
+## Install
-```
-npm install eslint-plugin-rxjs --save-dev
-```
+See [typescript-eslint's Getting Started](https://typescript-eslint.io/getting-started) for a full ESLint setup guide.
-Configure the `parser` and the `parserOptions` for ESLint. Here, I use a `.eslintrc.js` file for the configuration:
+Then use the `recommended` configuration in your `eslint.config.mjs` and enable typed linting:
```js
-const { join } = require("path");
-module.exports = {
- parser: "@typescript-eslint/parser",
- parserOptions: {
- ecmaVersion: 2019,
- project: join(__dirname, "./tsconfig.json"),
- sourceType: "module"
- },
- plugins: ["rxjs"],
- extends: [],
- rules: {
- "rxjs/no-async-subscribe": "error",
- "rxjs/no-ignored-observable": "error",
- "rxjs/no-ignored-subscription": "error",
- "rxjs/no-nested-subscribe": "error",
- "rxjs/no-unbound-methods": "error",
- "rxjs/throw-error": "error"
- }
-};
+// @ts-check
+import tseslint from 'typescript-eslint';
+import rxjsX from 'eslint-plugin-rxjs-x';
+
+export default tseslint.config({
+ extends: [
+ ...tseslint.configs.recommended,
+ rxjsX.configs.recommended,
+ ],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ },
+ },
+});
```
-Or, using the `recommended` configuration:
+The above example uses `typescript-eslint`'s built-in config to set up the TypeScript parser for us.
+Enabling `projectService` then turns on typed linting.
+See [Linting with Type Information](https://typescript-eslint.io/getting-started/typed-linting/) for details.
-```js
-const { join } = require("path");
-module.exports = {
- parser: "@typescript-eslint/parser",
- parserOptions: {
- ecmaVersion: 2019,
- project: join(__dirname, "./tsconfig.json"),
- sourceType: "module"
- },
- extends: ["plugin:rxjs/recommended"],
-};
-```
+## Configs
+
+
+
+| | Name |
+| :- | :------------ |
+| β
| `recommended` |
+| π | `strict` |
+
+
-# Rules
+## Rules
The package includes the following rules.
-Rules marked with β
are recommended and rules marked with π§ have fixers.
-
-| Rule | Description | | |
-| --- | --- | --- | --- |
-| [`ban-observables`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/ban-observables.md) | Forbids the use of banned observables. | | |
-| [`ban-operators`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/ban-operators.md) | Forbids the use of banned operators. | | |
-| [`finnish`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/finnish.md) | Enforces the use of Finnish notation. | | |
-| [`just`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/just.md) | Enforces the use of a `just` alias for `of`. | | π§ |
-| [`no-async-subscribe`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-async-subscribe.md) | Forbids passing `async` functions to `subscribe`. | β
| |
-| [`no-compat`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-compat.md) | Forbids importation from locations that depend upon `rxjs-compat`. | | |
-| [`no-connectable`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-connectable.md) | Forbids operators that return connectable observables. | | |
-| [`no-create`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-create.md) | Forbids the calling of `Observable.create`. | β
| |
-| [`no-cyclic-action`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-cyclic-action.md) | Forbids effects and epics that re-emit filtered actions. | | |
-| [`no-explicit-generics`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-explicit-generics.md) | Forbids explicit generic type arguments. | | |
-| [`no-exposed-subjects`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-exposed-subjects.md) | Forbids exposed (i.e. non-private) subjects. | | |
-| [`no-finnish`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-finnish.md) | Forbids the use of Finnish notation. | | |
-| [`no-ignored-error`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-error.md) | Forbids the calling of `subscribe` without specifying an error handler. | | |
-| [`no-ignored-notifier`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-notifier.md) | Forbids observables not composed from the `repeatWhen` or `retryWhen` notifier. | β
| |
-| [`no-ignored-observable`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-observable.md) | Forbids the ignoring of observables returned by functions. | | |
-| [`no-ignored-replay-buffer`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-replay-buffer.md) | Forbids using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | β
| |
-| [`no-ignored-subscribe`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-subscribe.md) | Forbids the calling of `subscribe` without specifying arguments. | | |
-| [`no-ignored-subscription`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-subscription.md) | Forbids ignoring the subscription returned by `subscribe`. | | |
-| [`no-ignored-takewhile-value`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-ignored-takewhile-value.md) | Forbids ignoring the value within `takeWhile`. | β
| |
-| [`no-implicit-any-catch`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-implicit-any-catch.md) | Like the [`no-implicit-any-catch` rule](https://github.com/typescript-eslint/typescript-eslint/pull/2202) in `@typescript-eslint/eslint-plugin`, but for the `catchError` operator instead of `catch` clauses. | β
| π§ |
-| [`no-index`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-index.md) | Forbids the importation from index modules - for the reason, see [this issue](https://github.com/ReactiveX/rxjs/issues/4230). | β
| |
-| [`no-internal`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-internal.md) | Forbids the importation of internals. | β
| π§ |
-| [`no-nested-subscribe`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-nested-subscribe.md) | Forbids the calling of `subscribe` within a `subscribe` callback. | β
| |
-| [`no-redundant-notify`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-redundant-notify.md) | Forbids redundant notifications from completed or errored observables. | β
| |
-| [`no-sharereplay`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-sharereplay.md) | Forbids using the `shareReplay` operator. | β
| |
-| [`no-subclass`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-subclass.md) | Forbids subclassing RxJS classes. | | |
-| [`no-subject-unsubscribe`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-subject-unsubscribe.md) | Forbids calling the `unsubscribe` method of a subject instance. | β
| |
-| [`no-subject-value`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-subject-value.md) | Forbids accessing the `value` property of a `BehaviorSubject` instance. | | |
-| [`no-subscribe-handlers`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-subscribe-handlers.md) | Forbids the passing of handlers to `subscribe`. | | |
-| [`no-topromise`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-topromise.md) | Forbids the use of the `toPromise` method. | | |
-| [`no-unbound-methods`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unbound-methods.md) | Forbids the passing of unbound methods. | β
| |
-| [`no-unsafe-catch`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-catch.md) | Forbids unsafe `catchError` usage in effects and epics. | | |
-| [`no-unsafe-first`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-first.md) | Forbids unsafe `first`/`take` usage in effects and epics. | | |
-| [`no-unsafe-subject-next`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-subject-next.md) | Forbids unsafe optional `next` calls. | β
| |
-| [`no-unsafe-switchmap`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-switchmap.md) | Forbids unsafe `switchMap` usage in effects and epics. | | |
-| [`no-unsafe-takeuntil`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/no-unsafe-takeuntil.md) | Forbids the application of operators after `takeUntil`. | β
| |
-| [`prefer-observer`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/prefer-observer.md) | Forbids the passing separate handlers to `subscribe` and `tap`. | | π§ |
-| [`suffix-subjects`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/suffix-subjects.md) | Enforces the use of a suffix in subject identifiers. | | |
-| [`throw-error`](https://github.com/cartant/eslint-plugin-rxjs/blob/main/docs/rules/throw-error.md) | Enforces the passing of `Error` values to error notifications. | | |
+
+
+πΌ Configurations enabled in.\
+β
Set in the `recommended` configuration.\
+π Set in the `strict` configuration.\
+π§ Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
+π‘ Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\
+π Requires [type information](https://typescript-eslint.io/linting/typed-linting).\
+β Deprecated.
+
+| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β | Description | πΌ | π§ | π‘ | π | β |
+| :--------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :--- | :- | :- | :- | :- |
+| [ban-observables](docs/rules/ban-observables.md) | Disallow banned observable creators. | | | | | |
+| [ban-operators](docs/rules/ban-operators.md) | Disallow banned operators. | | | | π | |
+| [finnish](docs/rules/finnish.md) | Enforce Finnish notation. | | | | π | |
+| [just](docs/rules/just.md) | Require the use of `just` instead of `of`. | | π§ | | | |
+| [macro](docs/rules/macro.md) | Require the use of the RxJS Tools Babel macro. | | π§ | | | β |
+| [no-async-subscribe](docs/rules/no-async-subscribe.md) | Disallow passing `async` functions to `subscribe`. | β
π | | | π | |
+| [no-compat](docs/rules/no-compat.md) | Disallow the `rxjs-compat` package. | | | | | β |
+| [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | π | |
+| [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | β
π | | | π | |
+| [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | π | |
+| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | π | | | | |
+| [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | π | | | π | |
+| [no-finnish](docs/rules/no-finnish.md) | Disallow Finnish notation. | | | | π | |
+| [no-floating-observables](docs/rules/no-floating-observables.md) | Require Observables to be handled appropriately. | π | | | π | |
+| [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | π | | | π | |
+| [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | π | | | π | |
+| [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | β
π | | | π | |
+| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | β
π | | | | |
+| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | π | |
+| [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | π | |
+| [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md) | Disallow ignoring the value within `takeWhile`. | β
π | | | | |
+| [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError` operators. | β
π | π§ | π‘ | π | |
+| [no-index](docs/rules/no-index.md) | Disallow importing index modules. | β
π | | | | |
+| [no-internal](docs/rules/no-internal.md) | Disallow importing internal modules. | β
π | π§ | π‘ | | |
+| [no-misused-observables](docs/rules/no-misused-observables.md) | Disallow Observables in places not designed to handle them. | π | | | π | |
+| [no-nested-subscribe](docs/rules/no-nested-subscribe.md) | Disallow calling `subscribe` within a `subscribe` callback. | β
π | | | π | |
+| [no-redundant-notify](docs/rules/no-redundant-notify.md) | Disallow sending redundant notifications from completed or errored observables. | β
π | | | π | |
+| [no-sharereplay](docs/rules/no-sharereplay.md) | Disallow unsafe `shareReplay` usage. | β
π | | | | |
+| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | π | | | π | |
+| [no-subject-unsubscribe](docs/rules/no-subject-unsubscribe.md) | Disallow calling the `unsubscribe` method of subjects. | β
π | | | π | |
+| [no-subject-value](docs/rules/no-subject-value.md) | Disallow accessing the `value` property of a `BehaviorSubject` instance. | | | | π | |
+| [no-subscribe-handlers](docs/rules/no-subscribe-handlers.md) | Disallow passing handlers to `subscribe`. | | | | π | |
+| [no-subscribe-in-pipe](docs/rules/no-subscribe-in-pipe.md) | Disallow calling of `subscribe` within any RxJS operator inside a `pipe`. | β
π | | | π | |
+| [no-tap](docs/rules/no-tap.md) | Disallow the `tap` operator. | | | | | β |
+| [no-topromise](docs/rules/no-topromise.md) | Disallow use of the `toPromise` method. | β
π | | π‘ | π | |
+| [no-unbound-methods](docs/rules/no-unbound-methods.md) | Disallow passing unbound methods. | β
π | | | π | |
+| [no-unsafe-catch](docs/rules/no-unsafe-catch.md) | Disallow unsafe `catchError` usage in effects and epics. | | | | π | |
+| [no-unsafe-first](docs/rules/no-unsafe-first.md) | Disallow unsafe `first`/`take` usage in effects and epics. | | | | π | |
+| [no-unsafe-subject-next](docs/rules/no-unsafe-subject-next.md) | Disallow unsafe optional `next` calls. | β
π | | | π | |
+| [no-unsafe-switchmap](docs/rules/no-unsafe-switchmap.md) | Disallow unsafe `switchMap` usage in effects and epics. | | | | π | |
+| [no-unsafe-takeuntil](docs/rules/no-unsafe-takeuntil.md) | Disallow applying operators after `takeUntil`. | β
π | | | π | |
+| [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | β
π | π§ | π‘ | π | |
+| [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | β
π | π§ | π‘ | | |
+| [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | π | |
+| [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError`. | β
π | | | π | |
+
+
diff --git a/docs/rules/ban-observables.md b/docs/rules/ban-observables.md
index c818a78f..a03d9a20 100644
--- a/docs/rules/ban-observables.md
+++ b/docs/rules/ban-observables.md
@@ -1,4 +1,6 @@
-# Avoid banned observable creators (`ban-observables`)
+# Disallow banned observable creators (`rxjs-x/ban-observables`)
+
+
This rule can be configured so that developers can ban any observable creators they want to avoid in their project.
@@ -10,7 +12,7 @@ The following configuration bans `partition` and `onErrorResumeNext`:
```json
{
- "rxjs/ban-observables": [
+ "rxjs-x/ban-observables": [
"error",
{
"partition": true,
@@ -19,4 +21,4 @@ The following configuration bans `partition` and `onErrorResumeNext`:
}
]
}
-```
\ No newline at end of file
+```
diff --git a/docs/rules/ban-operators.md b/docs/rules/ban-operators.md
index 5cab0a3d..38d824c2 100644
--- a/docs/rules/ban-operators.md
+++ b/docs/rules/ban-operators.md
@@ -1,4 +1,8 @@
-# Avoid banned operators (`ban-operators`)
+# Disallow banned operators (`rxjs-x/ban-operators`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule can be configured so that developers can ban any operators they want to avoid in their project.
@@ -10,7 +14,7 @@ The following configuration bans `partition` and `onErrorResumeNext`:
```json
{
- "rxjs/ban-operators": [
+ "rxjs-x/ban-operators": [
"error",
{
"partition": true,
diff --git a/docs/rules/finnish.md b/docs/rules/finnish.md
index 5f030da7..08aa671d 100644
--- a/docs/rules/finnish.md
+++ b/docs/rules/finnish.md
@@ -1,4 +1,8 @@
-# Use Finnish notation (`finnish`)
+# Enforce Finnish notation (`rxjs-x/finnish`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule enforces the use of Finnish notation - i.e. the `$` suffix.
@@ -18,16 +22,31 @@ const answer$ = of(42, 54);
## Options
+
+
+| Name | Description | Type |
+| :----------- | :------------------------------------------------------------------- | :------ |
+| `functions` | Require for functions. | Boolean |
+| `methods` | Require for methods. | Boolean |
+| `names` | Enforce for specific names. Keys are a RegExp, values are a boolean. | Object |
+| `parameters` | Require for parameters. | Boolean |
+| `properties` | Require for properties. | Boolean |
+| `strict` | Disallow Finnish notation for non-Observables. | Boolean |
+| `types` | Enforce for specific types. Keys are a RegExp, values are a boolean. | Object |
+| `variables` | Require for variables. | Boolean |
+
+
+
This rule accepts a single option which is an object with properties that determine whether Finnish notation is enforced for `functions`, `methods`, `parameters`, `properties` and `variables`. It also contains:
-- `names` and `types` properties that determine whether of not Finnish notation is to be enforced for specific names or types.
-- a `strict` property that, if `true`, allows the `$` suffix to be used _only_ with identifiers that have an `Observable` type.
+- `names` and `types` properties that determine whether or not Finnish notation is to be enforced for specific names or types.
+- a `strict` property that, if `true`, allows the `$` suffix to be used _only_ with identifiers that have an `Observable` type.
The default (Angular-friendly) configuration looks like this:
```json
{
- "rxjs/finnish": [
+ "rxjs-x/finnish": [
"error",
{
"functions": true,
@@ -51,4 +70,4 @@ The properties in the options object are themselves optional; they do not all ha
## Further reading
-- [Observables and Finnish Notation](https://medium.com/@benlesh/observables-and-finnish-notation-df8356ed1c9b)
+- [Observables and Finnish Notation](https://medium.com/@benlesh/observables-and-finnish-notation-df8356ed1c9b)
diff --git a/docs/rules/just.md b/docs/rules/just.md
index a1759309..157cfd73 100644
--- a/docs/rules/just.md
+++ b/docs/rules/just.md
@@ -1,11 +1,11 @@
-# Use `just` instead of `of` (`just`)
+# Require the use of `just` instead of `of` (`rxjs-x/just`)
-This rule enforces the use of `just` instead of `of`. Some other languages with Rx implementations use the former and this rule is for developers who have that preference.
+π§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
-## Options
+
-This rule has no options.
+This rule enforces the use of `just` instead of `of`. Some other languages with Rx implementations use the former and this rule is for developers who have that preference.
## Further reading
-- [Rename `of` to `just`](https://github.com/ReactiveX/rxjs/issues/3747)
\ No newline at end of file
+- [Rename `of` to `just`](https://github.com/ReactiveX/rxjs/issues/3747)
diff --git a/docs/rules/macro.md b/docs/rules/macro.md
index d1893769..7366475f 100644
--- a/docs/rules/macro.md
+++ b/docs/rules/macro.md
@@ -1,7 +1,11 @@
-# Use the RxJS Tools macro (`macro`)
+# Require the use of the RxJS Tools Babel macro (`rxjs-x/macro`)
-This rule ensures that modules that import `rxjs` also import the Babel macro for [RxJS Tools](https://rxjs.tools).
+β This rule is deprecated.
+
+π§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
-## Options
+
+
+This rule ensures that modules that import `rxjs` also import the Babel macro for [RxJS Tools](https://rxjs.tools).
-This rule has no options.
\ No newline at end of file
+This rule is deprecated because [`babel-plugin-rxjs-tools`](https://www.npmjs.com/package/babel-plugin-rxjs-tools) is unmaintained.
diff --git a/docs/rules/no-async-subscribe.md b/docs/rules/no-async-subscribe.md
index a5267751..a18c37f4 100644
--- a/docs/rules/no-async-subscribe.md
+++ b/docs/rules/no-async-subscribe.md
@@ -1,6 +1,15 @@
-# Avoid passing async functions to `subscribe` (`no-async-subscribe`)
+# Disallow passing `async` functions to `subscribe` (`rxjs-x/no-async-subscribe`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if async functions are passed to `subscribe`.
+Developers are encouraged to avoid race conditions
+by instead using RxJS operators which can handle both Promises and Observables
+(e.g. `concatMap`, `switchMap`, `mergeMap`, `exhaustMap`).
## Rule details
@@ -8,16 +17,26 @@ Examples of **incorrect** code for this rule:
```ts
import { of } from "rxjs";
-of(42).subscribe(async () => console.log(value));
+
+of(42).subscribe(async value => {
+ const data1 = await fetch(`https://api.some.com/things/${value}`);
+ const data2 = await fetch(`https://api.some.com/things/${data1.id}`);
+ console.log(data2);
+});
```
Examples of **correct** code for this rule:
```ts
import { of } from "rxjs";
-of(42).subscribe(() => console.log(value));
+
+of(42).pipe(
+ switchMap(value => fetch(`http://api.some.com/things/${value}`)),
+ switchMap(data1 => fetch(`http://api.some.com/things/${data1.id}`)),
+).subscribe(data2 => console.log(data2));
```
-## Options
+## Further reading
-This rule has no options.
+- [Why does this rule exist?](https://stackoverflow.com/q/71559135)
+- [Higher-order Observables](https://rxjs.dev/guide/higher-order-observables)
diff --git a/docs/rules/no-compat.md b/docs/rules/no-compat.md
index f4bf8968..a071a443 100644
--- a/docs/rules/no-compat.md
+++ b/docs/rules/no-compat.md
@@ -1,11 +1,13 @@
-# Avoid the `rxjs-compat` package (`no-compat`)
+# Disallow the `rxjs-compat` package (`rxjs-x/no-compat`)
-This rule prevents the use of `rxjs-compat`.
+β This rule is deprecated.
-## Options
+
-This rule has no options.
+This rule prevents importing from locations that depend upon the `rxjs-compat` package.
+
+This rule is deprecated because RxJS v7+ no longer includes `rxjs-compat`.
## Further reading
-- [Backwards compatibility](https://github.com/ReactiveX/rxjs/blob/a6590e971969c736a15b77154dabbc22275aa0d5/docs_app/content/guide/v6/migration.md#backwards-compatibility)
\ No newline at end of file
+- [Backwards compatibility](https://github.com/ReactiveX/rxjs/blob/a6590e971969c736a15b77154dabbc22275aa0d5/docs_app/content/guide/v6/migration.md#backwards-compatibility)
diff --git a/docs/rules/no-connectable.md b/docs/rules/no-connectable.md
index 0a2a9204..c7be7d76 100644
--- a/docs/rules/no-connectable.md
+++ b/docs/rules/no-connectable.md
@@ -1,7 +1,7 @@
-# Avoid connectable observables (`no-connectable`)
+# Disallow operators that return connectable observables (`rxjs-x/no-connectable`)
-This rule prevents the use of connectable observables.
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
-## Options
+
-This rule has no options.
\ No newline at end of file
+This rule prevents the use of connectable observables.
diff --git a/docs/rules/no-create.md b/docs/rules/no-create.md
index da1dbeb4..65aaa301 100644
--- a/docs/rules/no-create.md
+++ b/docs/rules/no-create.md
@@ -1,4 +1,10 @@
-# Avoid the static `create` function (`no-create`)
+# Disallow the static `Observable.create` function (`rxjs-x/no-create`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule prevents the use of the static `create` function in `Observable`. Developers should use `new` and the constructor instead.
@@ -23,7 +29,3 @@ const answers = new Observable(subscriber => {
subscriber.complete();
});
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-cyclic-action.md b/docs/rules/no-cyclic-action.md
index ece5b5a6..f2464e7e 100644
--- a/docs/rules/no-cyclic-action.md
+++ b/docs/rules/no-cyclic-action.md
@@ -1,4 +1,8 @@
-# Avoid cyclic actions in effects and epics (`no-cyclic-action`)
+# Disallow cyclic actions in effects and epics (`rxjs-x/no-cyclic-action`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures for effects and epics that emit actions that would pass their `ofType` filter. Such actions are cyclic and, upon emission, immediately re-trigger the effect or epic.
@@ -22,7 +26,7 @@ actions.pipe(
);
```
-This rule can be used with effects _and epics_, so it makes __no attempt__ to discern whether or not dispatching is disabled for an NgRx effect. That is, code like this will effect (π) a failure:
+This rule can be used with effects _and epics_, so it makes **no attempt** to discern whether or not dispatching is disabled for an NgRx effect. That is, code like this will effect (π) a failure:
```ts
someEffect = createEffect(() =>
@@ -50,13 +54,21 @@ Or you can use an ESLint [inline comment](https://eslint.org/docs/user-guide/con
## Options
+
+
+| Name | Description | Type | Default |
+| :----------- | :------------------------------------------------------------ | :----- | :----------------------- |
+| `observable` | A RegExp that matches an effect or epic's actions observable. | String | `[Aa]ction(s\|s\$\|\$)$` |
+
+
+
This rule accepts a single option which is an object with an `observable` property that is a regular expression used to match an effect or epic's actions observable. The default `observable` regular expression should match most effect and epic action sources.
```json
{
- "rxjs/no-cyclic-action": [
+ "rxjs-x/no-cyclic-action": [
"error",
{ "observable": "[Aa]ction(s|s\\$|\\$)$" }
]
}
-```
\ No newline at end of file
+```
diff --git a/docs/rules/no-explicit-generics.md b/docs/rules/no-explicit-generics.md
index 7d2a6b6c..e249d050 100644
--- a/docs/rules/no-explicit-generics.md
+++ b/docs/rules/no-explicit-generics.md
@@ -1,4 +1,8 @@
-# Avoid unnecessary explicit type arguments (`no-explicit-generics`)
+# Disallow unnecessary explicit generic type arguments (`rxjs-x/no-explicit-generics`)
+
+πΌ This rule is enabled in the π `strict` config.
+
+
This rule prevents the use of explicit type arguments when the type arguments can be inferred.
@@ -17,7 +21,3 @@ Examples of **correct** code for this rule:
import { BehaviorSubject } from "rxjs";
const subject = new BehaviorSubject(42);
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-exposed-subjects.md b/docs/rules/no-exposed-subjects.md
index 62f2402f..a86d5081 100644
--- a/docs/rules/no-exposed-subjects.md
+++ b/docs/rules/no-exposed-subjects.md
@@ -1,6 +1,12 @@
-# Avoid public and protected subjects (`no-exposed-subjects`)
+# Disallow public and protected subjects (`rxjs-x/no-exposed-subjects`)
-This rule prevents the public or protected subjects. Developers should instead expose observables via the subjects' `toObservable` method.
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule prevents exposed (i.e. non-private) subjects. Developers should instead expose observables via the subjects' `asObservable` method.
## Rule details
@@ -20,20 +26,28 @@ import { Subject } from "rxjs";
class Answers {
private _answers: Subject;
get answers() {
- return this._answers.toObservable();
+ return this._answers.asObservable();
}
}
```
## Options
+
+
+| Name | Description | Type | Default |
+| :--------------- | :------------------------ | :------ | :------ |
+| `allowProtected` | Allow protected subjects. | Boolean | `false` |
+
+
+
This rule accepts a single option which is an object with an `allowProtected` property that determines whether or not protected subjects are allowed. By default, they are not.
```json
{
- "rxjs/no-exposed-subjects": [
+ "rxjs-x/no-exposed-subjects": [
"error",
{ "allowProtected": true }
]
}
-```
\ No newline at end of file
+```
diff --git a/docs/rules/no-finnish.md b/docs/rules/no-finnish.md
index 5bc7c9a1..f13a7261 100644
--- a/docs/rules/no-finnish.md
+++ b/docs/rules/no-finnish.md
@@ -1,4 +1,8 @@
-# Avoid Finnish notation (`no-finnish`)
+# Disallow Finnish notation (`rxjs-x/no-finnish`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule prevents the use of Finnish notation.
@@ -16,10 +20,6 @@ Examples of **correct** code for this rule:
const answers = of(42, 54);
```
-## Options
-
-This rule has no options.
-
## Further reading
-- [Observables and Finnish Notation](https://medium.com/@benlesh/observables-and-finnish-notation-df8356ed1c9b)
\ No newline at end of file
+- [Observables and Finnish Notation](https://medium.com/@benlesh/observables-and-finnish-notation-df8356ed1c9b)
diff --git a/docs/rules/no-floating-observables.md b/docs/rules/no-floating-observables.md
new file mode 100644
index 00000000..3e829ed3
--- /dev/null
+++ b/docs/rules/no-floating-observables.md
@@ -0,0 +1,48 @@
+# Require Observables to be handled appropriately (`rxjs-x/no-floating-observables`)
+
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+A "floating" observable is one that is created without any code set up to handle any errors it might emit.
+Like a floating Promise, floating observables can cause several issues, such as ignored errors, unhandled cold observables, and more.
+
+This rule is like [no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/) but for Observables.
+This rule will report observable-valued statements that are not treated in one of the following ways:
+
+- Calling its `.subscribe()`
+- `return`ing it
+- Wrapping it in `lastValueFrom` or `firstValueFrom` and `await`ing it
+- [`void`ing it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void)
+
+> [!TIP]
+> `no-floating-observables` only detects apparently unhandled observable _statements_.
+> See [`no-misused-observables`](./no-misused-observables.md) for detecting code that provides observables to _logical_ locations
+
+## Rule details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+import { of } from "rxjs";
+of(42, 54);
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+import { of } from "rxjs";
+const answers = of(42, 54);
+```
+
+## Options
+
+
+
+| Name | Description | Type | Default |
+| :----------- | :------------------------------------ | :------ | :------ |
+| `ignoreVoid` | Whether to ignore `void` expressions. | Boolean | `true` |
+
+
diff --git a/docs/rules/no-ignored-default-value.md b/docs/rules/no-ignored-default-value.md
new file mode 100644
index 00000000..0b82010d
--- /dev/null
+++ b/docs/rules/no-ignored-default-value.md
@@ -0,0 +1,31 @@
+# Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value (`rxjs-x/no-ignored-default-value`)
+
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule prevents `EmptyError` rejections if there were no emissions from `firstValueFrom`, `lastValueFrom`, `first`, or `last` by requiring `defaultValue`.
+
+## Rule details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+import { Subject, firstValueFrom } from "rxjs";
+
+const sub = new Subject();
+const result = firstValueFrom(sub);
+sub.complete();
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+import { Subject, firstValueFrom } from "rxjs";
+
+const sub = new Subject();
+const result = firstValueFrom(sub, { defaultValue: null });
+sub.complete();
+```
diff --git a/docs/rules/no-ignored-error.md b/docs/rules/no-ignored-error.md
index da94bcb8..040bf4a5 100644
--- a/docs/rules/no-ignored-error.md
+++ b/docs/rules/no-ignored-error.md
@@ -1,4 +1,10 @@
-# Enforce the passing of error handlers (`no-ignored-error`)
+# Disallow calling `subscribe` without specifying an error handler (`rxjs-x/no-ignored-error`)
+
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule enforces the passing of an error handler to `subscribe` calls.
@@ -31,7 +37,3 @@ source.subscribe({
error: (error) => console.error(error)
});
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-ignored-notifier.md b/docs/rules/no-ignored-notifier.md
index cd07f953..06bd6202 100644
--- a/docs/rules/no-ignored-notifier.md
+++ b/docs/rules/no-ignored-notifier.md
@@ -1,4 +1,10 @@
-# Ensure `repeatWhen` or `retryWhen` notifiers are used (`no-ignored-notifier`)
+# Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier (`rxjs-x/no-ignored-notifier`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if the notifier passed to a `repeatWhen` or `retryWhen` callback is not used.
@@ -24,7 +30,3 @@ const repeating = source.pipe(
repeatWhen(notifications => notifications.pipe(take(3)))
);
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-ignored-observable.md b/docs/rules/no-ignored-observable.md
deleted file mode 100644
index 45df0619..00000000
--- a/docs/rules/no-ignored-observable.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Use returned observables (`no-ignored-observable`)
-
-The effects failures if an observable returned by a function is neither assigned to a variable or property or passed to a function.
-
-## Rule details
-
-Examples of **incorrect** code for this rule:
-
-```ts
-import { of } from "rxjs";
-of(42, 54);
-```
-
-Examples of **correct** code for this rule:
-
-```ts
-import { of } from "rxjs";
-const answers = of(42, 54);
-```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-ignored-replay-buffer.md b/docs/rules/no-ignored-replay-buffer.md
index 7b245a2b..c53326bc 100644
--- a/docs/rules/no-ignored-replay-buffer.md
+++ b/docs/rules/no-ignored-replay-buffer.md
@@ -1,4 +1,8 @@
-# Avoid unbounded replay buffers (`no-ignored-replay-buffer`)
+# Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size (`rxjs-x/no-ignored-replay-buffer`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+
This rule effects failures if the buffer size of a replay buffer is not explicitly specified.
@@ -11,6 +15,11 @@ import { ReplaySubject } from "rxjs";
const subject = new ReplaySubject();
```
+```ts
+import { of, shareReplay } from "rxjs";
+of(42).pipe(shareReplay({ refCount: true }));
+```
+
Examples of **correct** code for this rule:
```ts
@@ -23,6 +32,7 @@ import { ReplaySubject } from "rxjs";
const subject = new ReplaySubject(Infinity);
```
-## Options
-
-This rule has no options.
\ No newline at end of file
+```ts
+import { of, shareReplay } from "rxjs";
+of(42).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
+```
diff --git a/docs/rules/no-ignored-subscribe.md b/docs/rules/no-ignored-subscribe.md
index 42f904dd..b557975c 100644
--- a/docs/rules/no-ignored-subscribe.md
+++ b/docs/rules/no-ignored-subscribe.md
@@ -1,4 +1,8 @@
-# Enforce the passing of handlers to `subscribe` (`no-ignored-subscribe`)
+# Disallow calling `subscribe` without specifying arguments (`rxjs-x/no-ignored-subscribe`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures whenever `subscribe` is called without handlers.
@@ -22,7 +26,3 @@ import { of } from "rxjs";
of(42, 54).subscribe((value) => console.log(value));
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-ignored-subscription.md b/docs/rules/no-ignored-subscription.md
index d4a5227b..2e09c6c1 100644
--- a/docs/rules/no-ignored-subscription.md
+++ b/docs/rules/no-ignored-subscription.md
@@ -1,4 +1,8 @@
-# Use returned subscriptions (`no-ignored-subscription`)
+# Disallow ignoring the subscription returned by `subscribe` (`rxjs-x/no-ignored-subscription`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
The effects failures if an subscription returned by call to `subscribe` is neither assigned to a variable or property or passed to a function.
@@ -27,7 +31,3 @@ const numbers = new Observable(subscriber => {
interval(1e3).subscribe(subscriber);
});
```
-
-## Options
-
-This rule has no options.
diff --git a/docs/rules/no-ignored-takewhile-value.md b/docs/rules/no-ignored-takewhile-value.md
index 70d91445..8a6bc625 100644
--- a/docs/rules/no-ignored-takewhile-value.md
+++ b/docs/rules/no-ignored-takewhile-value.md
@@ -1,4 +1,8 @@
-# Avoid unused `takeWhile` values (`no-ignored-takewhile-value`)
+# Disallow ignoring the value within `takeWhile` (`rxjs-x/no-ignored-takewhile-value`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+
This rule effects failures if the value received by a `takeWhile` callback is not used in an expression.
@@ -20,7 +24,3 @@ import { takeWhile } from "rxjs/operators";
const whilst = source.pipe(takeWhile(value => value));
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-implicit-any-catch.md b/docs/rules/no-implicit-any-catch.md
index 512ba329..4dd7b58c 100644
--- a/docs/rules/no-implicit-any-catch.md
+++ b/docs/rules/no-implicit-any-catch.md
@@ -1,6 +1,14 @@
-# Use type-safe error handlers (`no-implicit-any-catch`)
+# Disallow implicit `any` error parameters in `catchError` operators (`rxjs-x/no-implicit-any-catch`)
-This rule requires an explicit type annotation for error parameters in error handlers. It's similar to the TypeScript [`no-implicit-any-catch`](https://github.com/typescript-eslint/typescript-eslint/blob/e01204931e460f5e6731abc443c88d666ca0b07a/packages/eslint-plugin/docs/rules/no-implicit-any-catch.md) rule, but is for observables - not `try`/`catch` statements.
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π§π‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule requires an explicit type annotation for error parameters in error handlers. It's similar to the typescript-eslint [`use-unknown-in-catch-callback-variable`](https://typescript-eslint.io/rules/use-unknown-in-catch-callback-variable/) rule or the TSConfig [`useUnknownInCatchVariables`](https://www.typescriptlang.org/tsconfig/#useUnknownInCatchVariables) option, but is for observables - not `try`/`catch` statements.
## Rule details
@@ -62,11 +70,19 @@ throwError(() => new Error("Kaboom!")).pipe(
## Options
-This rule accepts a single option which is an object with an `allowExplicitAny` property that determines whether or not the error variable can be explicitly typed as `any`. By default, the use of explicit `any` is forbidden.
+
+
+| Name | Description | Type | Default |
+| :----------------- | :---------------------------------------------------- | :------ | :------ |
+| `allowExplicitAny` | Allow error variable to be explicitly typed as `any`. | Boolean | `true` |
+
+
+
+This rule accepts a single option which is an object with an `allowExplicitAny` property that determines whether or not the error variable can be explicitly typed as `any`. By default, the use of explicit `any` is allowed.
```json
{
- "rxjs/no-implicit-any-catch": [
+ "rxjs-x/no-implicit-any-catch": [
"error",
{ "allowExplicitAny": true }
]
@@ -75,4 +91,4 @@ This rule accepts a single option which is an object with an `allowExplicitAny`
## Further reading
-- [Catching Unknowns](https://ncjamieson.com/catching-unknowns/)
\ No newline at end of file
+- [Catching Unknowns](https://ncjamieson.com/catching-unknowns/)
diff --git a/docs/rules/no-index.md b/docs/rules/no-index.md
index 6aa60f33..123a6cee 100644
--- a/docs/rules/no-index.md
+++ b/docs/rules/no-index.md
@@ -1,4 +1,8 @@
-# Avoid importing index modules (`no-index`)
+# Disallow importing index modules (`rxjs-x/no-index`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+
This rule effects failures if an index module is specified as the import location.
@@ -15,7 +19,3 @@ Examples of **correct** code for this rule:
```ts
import { of } from "rxjs";
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-internal.md b/docs/rules/no-internal.md
index 73c8feab..20a2d79d 100644
--- a/docs/rules/no-internal.md
+++ b/docs/rules/no-internal.md
@@ -1,4 +1,10 @@
-# Avoid importing internal modules (`no-internal`)
+# Disallow importing internal modules (`rxjs-x/no-internal`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π§π‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
+
+
This rule effects failures if an internal module is specified as the import location.
@@ -15,7 +21,3 @@ Examples of **correct** code for this rule:
```ts
import { of } from "rxjs";
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-misused-observables.md b/docs/rules/no-misused-observables.md
new file mode 100644
index 00000000..64d9ab44
--- /dev/null
+++ b/docs/rules/no-misused-observables.md
@@ -0,0 +1,85 @@
+# Disallow Observables in places not designed to handle them (`rxjs-x/no-misused-observables`)
+
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule forbids providing observables to logical locations where the TypeScript compiler allows them but they are not handled properly.
+These situations can often arise due to a misunderstanding of the way observables are handled.
+
+> [!TIP]
+> `no-misused-observables` only detects code that provides observables to incorrect _logical_ locations.
+> See [`no-floating-observables`](./no-floating-observables.md) for detecting unhandled observable _statements_.
+
+This rule is like [no-misused-promises](https://typescript-eslint.io/rules/no-misused-promises) but for Observables.
+
+> [!NOTE]
+> Unlike `@typescript-eslint/no-misused-promises`, this rule does not check conditionals like `if` statements.
+> Use `@typescript-eslint/no-unnecessary-condition` for linting those situations.
+
+## Rule details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+import { of } from "rxjs";
+
+[1, 2, 3].forEach(i => of(i));
+
+interface MySyncInterface {
+ foo(): void;
+}
+class MyRxClass implements MySyncInterface {
+ foo(): Observable {
+ return of(42);
+ }
+}
+
+const a = of(42);
+const b = { ...b };
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+import { of } from "rxjs";
+
+[1, 2, 3].map(i => of(i));
+
+interface MyRxInterface {
+ foo(): Observable;
+}
+class MyRxClass implements MyRxInterface {
+ foo(): Observable {
+ return of(42);
+ }
+}
+```
+
+## Options
+
+
+
+| Name | Description | Type | Default |
+| :----------------- | :-------------------------------------------------------------------------- | :------ | :------ |
+| `checksSpreads` | Disallow `...` spreading an Observable. | Boolean | `true` |
+| `checksVoidReturn` | Disallow returning an Observable from a function typed as returning `void`. | Object | `true` |
+
+### `checksVoidReturn`
+
+You can disable selective parts of the `checksVoidReturn` option. The following sub-options are supported:
+
+| Name | Description | Type | Default |
+| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :------ | :------ |
+| `arguments` | Disallow passing an Observable-returning function as an argument where the parameter type expects a function that returns `void`. | Boolean | `true` |
+| `attributes` | Disallow passing an Observable-returning function as a JSX attribute expected to be a function that returns `void`. | Boolean | `true` |
+| `inheritedMethods` | Disallow providing an Observable-returning function where a function that returns `void` is expected by an extended or implemented type. | Boolean | `true` |
+| `properties` | Disallow providing an Observable-returning function where a function that returns `void` is expected by a property. | Boolean | `true` |
+| `returns` | Disallow returning an Observable-returning function where a function that returns `void` is expected. | Boolean | `true` |
+| `variables` | Disallow assigning or declaring an Observable-returning function where a function that returns `void` is expected. | Boolean | `true` |
+
+## Further reading
+
+- [TypeScript void function assignability](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void)
diff --git a/docs/rules/no-nested-subscribe.md b/docs/rules/no-nested-subscribe.md
index 57f660fa..ad222a44 100644
--- a/docs/rules/no-nested-subscribe.md
+++ b/docs/rules/no-nested-subscribe.md
@@ -1,4 +1,10 @@
-# Avoid nested `subscribe` calls (`no-nested-subscribe`)
+# Disallow calling `subscribe` within a `subscribe` callback (`rxjs-x/no-nested-subscribe`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `subscribe` is called within a `subscribe` handler.
@@ -18,13 +24,9 @@ Examples of **correct** code for this rule:
```ts
import { of, timer } from "rxjs";
-import { mapTo, mergeMap } from "rxjs/operators";
+import { map, mergeMap } from "rxjs/operators";
of(42, 54).pipe(
- mergeMap((value) => timer(1e3).pipe(mapTo(value)))
+ mergeMap((value) => timer(1e3).pipe(map(() => value)))
).subscribe((value) => console.log(value));
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-redundant-notify.md b/docs/rules/no-redundant-notify.md
index 4450d644..945ed49d 100644
--- a/docs/rules/no-redundant-notify.md
+++ b/docs/rules/no-redundant-notify.md
@@ -1,4 +1,10 @@
-# Avoid sending redundant notifications (`no-redundant-notify`)
+# Disallow sending redundant notifications from completed or errored observables (`rxjs-x/no-redundant-notify`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if an attempt is made to send a notification to an observer after a `complete` or `error` notification has already been sent.
@@ -26,7 +32,3 @@ const subject = new Subject();
subject.next(42);
subject.error(new Error("Kaboom!"));
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-sharereplay.md b/docs/rules/no-sharereplay.md
index 5d5db818..03042a55 100644
--- a/docs/rules/no-sharereplay.md
+++ b/docs/rules/no-sharereplay.md
@@ -1,16 +1,28 @@
-# Avoid `shareReplay` (`no-sharereplay`)
+# Disallow unsafe `shareReplay` usage (`rxjs-x/no-sharereplay`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+
This rule effects failures if the `shareReplay` operator is used - or if it is used without specifying a `config` argument.
-The behaviour of `shareReplay` has changed several times - see the blog post linked below.
+The behavior of `shareReplay` has changed several times - see the blog post linked below.
## Options
+
+
+| Name | Description | Type | Default |
+| :------------ | :--------------------------------------------------- | :------ | :------ |
+| `allowConfig` | Allow shareReplay if a config argument is specified. | Boolean | `true` |
+
+
+
This rule accepts a single option which is an object with an `allowConfig` property that that determines whether `shareReplay` is allow if a config argument is specified. By default, `allowConfig` is `true`.
```json
{
- "rxjs/no-sharereplay": [
+ "rxjs-x/no-sharereplay": [
"error",
{ "allowConfig": true }
]
@@ -19,4 +31,4 @@ This rule accepts a single option which is an object with an `allowConfig` prope
## Further reading
-- [What's changed with shareReplay](https://ncjamieson.com/whats-changed-with-sharereplay/)
\ No newline at end of file
+- [What's changed with shareReplay](https://ncjamieson.com/whats-changed-with-sharereplay/)
diff --git a/docs/rules/no-subclass.md b/docs/rules/no-subclass.md
index 5274790f..8ad58c94 100644
--- a/docs/rules/no-subclass.md
+++ b/docs/rules/no-subclass.md
@@ -1,7 +1,9 @@
-# Avoid subclassing RxJS classes (`no-subclass`)
+# Disallow subclassing RxJS classes (`rxjs-x/no-subclass`)
-This rule effects failures if an RxJS class is subclassed. Developers are encouraged to avoid subclassing RxJS classes, as some public and protected implementation details might change in the future.
+πΌ This rule is enabled in the π `strict` config.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
-## Options
+
-This rule has no options.
\ No newline at end of file
+This rule effects failures if an RxJS class is subclassed. Developers are encouraged to avoid subclassing RxJS classes, as some public and protected implementation details might change in the future.
diff --git a/docs/rules/no-subject-unsubscribe.md b/docs/rules/no-subject-unsubscribe.md
index 09443065..fa11b86e 100644
--- a/docs/rules/no-subject-unsubscribe.md
+++ b/docs/rules/no-subject-unsubscribe.md
@@ -1,11 +1,13 @@
-# Avoid calling `unsubscribe` on subjects (`no-subject-unsubscribe`)
+# Disallow calling the `unsubscribe` method of subjects (`rxjs-x/no-subject-unsubscribe`)
-This rule effects failures if the `unsubscribe` method is called on subjects. The method behaves differently to the `unsubsribe` method on subscriptions and is often an error.
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
-## Options
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
-This rule has no options.
+
+
+This rule effects failures if the `unsubscribe` method is called on subjects. The method behaves differently to the `unsubscribe` method on subscriptions and is often an error.
## Further reading
-- [Closed Subjects](https://ncjamieson.com/closed-subjects/)
\ No newline at end of file
+- [Closed Subjects](https://ncjamieson.com/closed-subjects/)
diff --git a/docs/rules/no-subject-value.md b/docs/rules/no-subject-value.md
index 7454f08b..f7fb9e50 100644
--- a/docs/rules/no-subject-value.md
+++ b/docs/rules/no-subject-value.md
@@ -1,7 +1,7 @@
-# Avoid using a behavior subject's value (`no-subject-value`)
+# Disallow accessing the `value` property of a `BehaviorSubject` instance (`rxjs-x/no-subject-value`)
-This rule effects an error if the `value` property - or `getValue` method - of a `BehaviorSubject` is used.
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
-## Options
+
-This rule has no options.
\ No newline at end of file
+This rule effects an error if the `value` property - or `getValue` method - of a `BehaviorSubject` is used.
diff --git a/docs/rules/no-subscribe-handlers.md b/docs/rules/no-subscribe-handlers.md
index 2293ffe0..0b2742e9 100644
--- a/docs/rules/no-subscribe-handlers.md
+++ b/docs/rules/no-subscribe-handlers.md
@@ -1,4 +1,8 @@
-# Forbid the passing of handlers to `subscribe` (`no-subscribe-handlers`)
+# Disallow passing handlers to `subscribe` (`rxjs-x/no-subscribe-handlers`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures whenever `subscribe` is called with handlers.
@@ -13,7 +17,6 @@ import { tap } from "rxjs/operators";
of(42, 54).subscribe((value) => console.log(value));
```
-
```ts
import { of } from "rxjs";
import { tap } from "rxjs/operators";
@@ -25,7 +28,6 @@ of(42, 54).subscribe({
Examples of **correct** code for this rule:
-
```ts
import { of } from "rxjs";
@@ -33,7 +35,3 @@ of(42, 54)
.pipe(tap((value) => console.log(value)))
.subscribe();
```
-
-## Options
-
-This rule has no options.
diff --git a/docs/rules/no-subscribe-in-pipe.md b/docs/rules/no-subscribe-in-pipe.md
new file mode 100644
index 00000000..24a6352c
--- /dev/null
+++ b/docs/rules/no-subscribe-in-pipe.md
@@ -0,0 +1,37 @@
+# Disallow calling of `subscribe` within any RxJS operator inside a `pipe` (`rxjs-x/no-subscribe-in-pipe`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule effects failures if `subscribe` is called within any operator inside a `pipe` operation.
+
+## Rule details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+import { of } from "rxjs";
+import { map } from "rxjs/operators";
+
+of(42, 54).pipe(
+ map(value => {
+ of(value).subscribe(console.log); // This will trigger the rule
+ return value * 2;
+ })
+).subscribe(result => console.log(result));
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+import { of } from "rxjs";
+import { map, tap } from "rxjs/operators";
+
+of(42, 54).pipe(
+ tap(value => console.log(value)),
+ map(value => value * 2)
+).subscribe(result => console.log(result));
+```
diff --git a/docs/rules/no-tap.md b/docs/rules/no-tap.md
index 2e109752..4eaf6690 100644
--- a/docs/rules/no-tap.md
+++ b/docs/rules/no-tap.md
@@ -1,7 +1,7 @@
-# Avoid `tap` (`no-tap`)
+# Disallow the `tap` operator (`rxjs-x/no-tap`)
-This rule effects failures if the `tap` operator is used.
+β This rule is deprecated. It was replaced by [`rxjs-x/ban-operators`](ban-operators.md).
-## Options
+
-This rule has no options.
\ No newline at end of file
+This rule effects failures if the `tap` operator is used.
diff --git a/docs/rules/no-topromise.md b/docs/rules/no-topromise.md
index 804df867..b62d3aa6 100644
--- a/docs/rules/no-topromise.md
+++ b/docs/rules/no-topromise.md
@@ -1,7 +1,15 @@
-# Avoid `toPromise` (`no-topromise`)
+# Disallow use of the `toPromise` method (`rxjs-x/no-topromise`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π‘ This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if the `toPromise` method is used.
-## Options
+## Further reading
-This rule has no options.
\ No newline at end of file
+- [Conversion to Promises](https://rxjs.dev/deprecations/to-promise)
diff --git a/docs/rules/no-unbound-methods.md b/docs/rules/no-unbound-methods.md
index 1d8fd6ba..8ac596f1 100644
--- a/docs/rules/no-unbound-methods.md
+++ b/docs/rules/no-unbound-methods.md
@@ -1,4 +1,10 @@
-# Avoid using unbound methods as callbacks (`no-unbound-methods`)
+# Disallow passing unbound methods (`rxjs-x/no-unbound-methods`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if unbound methods are passed as callbacks.
@@ -6,7 +12,6 @@ This rule effects failures if unbound methods are passed as callbacks.
Examples of **incorrect** code for this rule:
-
```ts
return this.http
.get("https://api.some.com/things/1")
@@ -18,7 +23,6 @@ return this.http
Examples of **correct** code for this rule:
-
```ts
return this.http
.get("https://api.some.com/things/1")
@@ -28,7 +32,6 @@ return this.http
);
```
-
```ts
return this.http
.get("https://api.some.com/things/1")
@@ -38,10 +41,6 @@ return this.http
);
```
-## Options
-
-This rule has no options.
-
## Further reading
- [Avoiding unbound methods](https://ncjamieson.com/avoiding-unbound-methods/)
diff --git a/docs/rules/no-unsafe-catch.md b/docs/rules/no-unsafe-catch.md
index b0d1c39a..53ad2caa 100644
--- a/docs/rules/no-unsafe-catch.md
+++ b/docs/rules/no-unsafe-catch.md
@@ -1,4 +1,8 @@
-# Avoid completing effects and epics (`no-unsafe-catch`)
+# Disallow unsafe `catchError` usage in effects and epics (`rxjs-x/no-unsafe-catch`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `catchError` is used in an effect or epic in a manner that will complete the outermost observable.
@@ -38,13 +42,21 @@ actions.pipe(
## Options
+
+
+| Name | Description | Type | Default |
+| :----------- | :------------------------------------------------------------ | :----- | :----------------------- |
+| `observable` | A RegExp that matches an effect or epic's actions observable. | String | `[Aa]ction(s\|s\$\|\$)$` |
+
+
+
This rule accepts a single option which is an object with an `observable` property that is a regular expression used to match an effect or epic's actions observable. The default `observable` regular expression should match most effect and epic action sources.
```json
{
- "rxjs/no-unsafe-catch": [
+ "rxjs-x/no-unsafe-catch": [
"error",
{ "observable": "[Aa]ction(s|s\\$|\\$)$" }
]
}
-```
\ No newline at end of file
+```
diff --git a/docs/rules/no-unsafe-first.md b/docs/rules/no-unsafe-first.md
index cb124391..3f07d78d 100644
--- a/docs/rules/no-unsafe-first.md
+++ b/docs/rules/no-unsafe-first.md
@@ -1,16 +1,28 @@
-# Avoid completing effects and epics (`no-unsafe-first`)
+# Disallow unsafe `first`/`take` usage in effects and epics (`rxjs-x/no-unsafe-first`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `first` is used in an effect or epic in a manner that will complete the outermost observable.
## Options
+
+
+| Name | Description | Type | Default |
+| :----------- | :------------------------------------------------------------ | :----- | :----------------------- |
+| `observable` | A RegExp that matches an effect or epic's actions observable. | String | `[Aa]ction(s\|s\$\|\$)$` |
+
+
+
This rule accepts a single option which is an object with an `observable` property that is a regular expression used to match an effect or epic's actions observable. The default `observable` regular expression should match most effect and epic action sources.
```json
{
- "rxjs/no-unsafe-first": [
+ "rxjs-x/no-unsafe-first": [
"error",
{ "observable": "[Aa]ction(s|s\\$|\\$)$" }
]
}
-```
\ No newline at end of file
+```
diff --git a/docs/rules/no-unsafe-subject-next.md b/docs/rules/no-unsafe-subject-next.md
index 41e23e7e..a3eccf23 100644
--- a/docs/rules/no-unsafe-subject-next.md
+++ b/docs/rules/no-unsafe-subject-next.md
@@ -1,4 +1,10 @@
-# Avoid passing `undefined` to `next` (`no-unsafe-subject-next`)
+# Disallow unsafe optional `next` calls (`rxjs-x/no-unsafe-subject-next`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `next` is called without an argument and the subject's value type is not `void`.
@@ -24,7 +30,3 @@ subject.next();
const subject = new Subject();
subject.next(0);
```
-
-## Options
-
-This rule has no options.
\ No newline at end of file
diff --git a/docs/rules/no-unsafe-switchmap.md b/docs/rules/no-unsafe-switchmap.md
index fe2a3ed2..3cd327e4 100644
--- a/docs/rules/no-unsafe-switchmap.md
+++ b/docs/rules/no-unsafe-switchmap.md
@@ -1,9 +1,23 @@
-# Avoid `switchMap` bugs in effects and epics (`no-unsafe-switchmap`)
+# Disallow unsafe `switchMap` usage in effects and epics (`rxjs-x/no-unsafe-switchmap`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `switchMap` is used in effects or epics that perform actions other than reads. For a detailed explanation, see the blog post linked below.
## Options
+
+
+| Name | Description | Type | Default |
+| :----------- | :------------------------------------------------------------------------------------------- | :----- | :----------------------- |
+| `allow` | Action types that are allowed to be used with switchMap. Mutually exclusive with `disallow`. | | |
+| `disallow` | Action types that are disallowed to be used with switchMap. Mutually exclusive with `allow`. | | |
+| `observable` | A RegExp that matches an effect or epic's actions observable. | String | `[Aa]ction(s\|s\$\|\$)$` |
+
+
+
This rule accepts a single option which is an object with `allow`, `disallow` and `observable` properties.
The `observable` property is a regular expression used to match an effect or epic's actions observable. The default `observable` regular expression should match most effect and epic action sources.
@@ -12,7 +26,7 @@ The `allow` or `disallow` properties are mutually exclusive. Whether or not `swi
```json
{
- "rxjs/no-unsafe-switchmap": [
+ "rxjs-x/no-unsafe-switchmap": [
"error",
{
"disallow": [
@@ -35,4 +49,4 @@ The properties in the options object are themselves optional; they do not all ha
## Further reading
-- [Avoiding switchMap-related bugs](https://ncjamieson.com/avoiding-switchmap-related-bugs/)
\ No newline at end of file
+- [Avoiding switchMap-related bugs](https://ncjamieson.com/avoiding-switchmap-related-bugs/)
diff --git a/docs/rules/no-unsafe-takeuntil.md b/docs/rules/no-unsafe-takeuntil.md
index afebc8cc..8a2dda6e 100644
--- a/docs/rules/no-unsafe-takeuntil.md
+++ b/docs/rules/no-unsafe-takeuntil.md
@@ -1,4 +1,10 @@
-# Avoid `takeUntil` subscription leaks (`no-unsafe-takeuntil`)
+# Disallow applying operators after `takeUntil` (`rxjs-x/no-unsafe-takeuntil`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures whenever `takeUntil` is used in observable compositions that can leak subscriptions.
@@ -24,13 +30,22 @@ const combined = source
## Options
+
+
+| Name | Description | Type | Default |
+| :------ | :-------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `alias` | An array of operator names that should be treated similarly to `takeUntil`. | String[] | |
+| `allow` | An array of operator names that are allowed to follow `takeUntil`. | String[] | [`count`, `defaultIfEmpty`, `endWith`, `every`, `finalize`, `finally`, `isEmpty`, `last`, `max`, `min`, `publish`, `publishBehavior`, `publishLast`, `publishReplay`, `reduce`, `share`, `shareReplay`, `skipLast`, `takeLast`, `throwIfEmpty`, `toArray`] |
+
+
+
This rule accepts a single option which is an object with `alias` and `allow` properties. The `alias` property is an array of names of operators that should be treated similarly to `takeUntil` and the `allow` property is an array of names of operators that are safe to use after `takeUntil`.
By default, the `allow` property contains all of the built-in operators that are safe to use after `takeUntil`.
```json
{
- "rxjs/no-unsafe-takeuntil": [
+ "rxjs-x/no-unsafe-takeuntil": [
"error",
{
"alias": ["untilDestroyed"]
@@ -43,4 +58,4 @@ The properties in the options object are themselves optional; they do not all ha
## Further reading
-- [Avoiding takeUntil leaks](https://ncjamieson.com/avoiding-takeuntil-leaks/)
+- [Avoiding takeUntil leaks](https://ncjamieson.com/avoiding-takeuntil-leaks/)
diff --git a/docs/rules/prefer-observer.md b/docs/rules/prefer-observer.md
index 1204c6c4..ffb454f1 100644
--- a/docs/rules/prefer-observer.md
+++ b/docs/rules/prefer-observer.md
@@ -1,4 +1,12 @@
-# Avoid separate handlers (`prefer-observer`)
+# Disallow passing separate handlers to `subscribe` and `tap` (`rxjs-x/prefer-observer`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π§π‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if `subscribe` - or `tap` - is called with separate handlers instead of an observer.
@@ -22,13 +30,25 @@ of(42, 54).subscribe({
## Options
+
+
+| Name | Description | Type | Default |
+| :---------- | :------------------------------- | :------ | :------ |
+| `allowNext` | Allows a single `next` callback. | Boolean | `true` |
+
+
+
This rule accepts a single option which is an object with an `allowNext` property that determines whether a single `next` callback is allowed. By default, `allowNext` is `true`.
```json
{
- "rxjs/prefer-observer": [
+ "rxjs-x/prefer-observer": [
"error",
{ "allowNext": false }
]
}
-```
\ No newline at end of file
+```
+
+## Further reading
+
+- [Subscribe Arguments](https://rxjs.dev/deprecations/subscribe-arguments)
diff --git a/docs/rules/prefer-root-operators.md b/docs/rules/prefer-root-operators.md
new file mode 100644
index 00000000..1e6c33cf
--- /dev/null
+++ b/docs/rules/prefer-root-operators.md
@@ -0,0 +1,34 @@
+# Disallow importing operators from `rxjs/operators` (`rxjs-x/prefer-root-operators`)
+
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π§π‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
+
+
+
+This rule prevents importing from the `rxjs/operators` export site.
+Most operators were moved to the `rxjs` export site in RxJS v7.2.0
+(excepting a few old and deprecated operators).
+The `rxjs/operators` export site has since been deprecated and will be removed in a future major version.
+
+Note that because a few operators were renamed or not migrated to the `rxjs` export site,
+this rule may not provide an automatic fixer if renaming the import path is not guaranteed to be safe.
+See the documentation linked below.
+
+## Rule details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+import { map } from 'rxjs/operators';
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+import { map } from 'rxjs';
+```
+
+## Further reading
+
+- [Importing instructions](https://rxjs.dev/guide/importing)
diff --git a/docs/rules/suffix-subjects.md b/docs/rules/suffix-subjects.md
index 73cd2774..80b92c9c 100644
--- a/docs/rules/suffix-subjects.md
+++ b/docs/rules/suffix-subjects.md
@@ -1,4 +1,8 @@
-# Identify subjects (`suffix-subjects`)
+# Enforce the use of a suffix in subject identifiers (`rxjs-x/suffix-subjects`)
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
This rule effects failures if subject variables, properties and parameters don't conform to a naming scheme that identifies them as subjects.
@@ -18,13 +22,25 @@ const answersSubject = new Subject();
## Options
+
+
+| Name | Description | Type |
+| :----------- | :------------------------------------------------------------------- | :------ |
+| `parameters` | Require for parameters. | Boolean |
+| `properties` | Require for properties. | Boolean |
+| `suffix` | The suffix to enforce. | String |
+| `types` | Enforce for specific types. Keys are a RegExp, values are a boolean. | Object |
+| `variables` | Require for variables. | Boolean |
+
+
+
This rule accepts a single option which is an object with properties that determine whether Finnish notation is enforced for `parameters`, `properties` and `variables`. It also contains a `types` property that determine whether of not the naming convention is to be enforced for specific types and a `suffix` property.
The default (Angular-friendly) configuration looks like this:
```json
{
- "rxjs/suffix-subjects": [
+ "rxjs-x/suffix-subjects": [
"error",
{
"parameters": true,
@@ -39,4 +55,4 @@ The default (Angular-friendly) configuration looks like this:
}
```
-The properties in the options object are themselves optional; they do not all have to be specified.
\ No newline at end of file
+The properties in the options object are themselves optional; they do not all have to be specified.
diff --git a/docs/rules/throw-error.md b/docs/rules/throw-error.md
index 030db6ee..8f4f91f8 100644
--- a/docs/rules/throw-error.md
+++ b/docs/rules/throw-error.md
@@ -1,49 +1,40 @@
-# Avoid throwing non-Error values (`throw-error`)
+# Enforce passing only `Error` values to `throwError` (`rxjs-x/throw-error`)
-This rule forbids throwing values that are neither `Error` nor `DOMException` instances.
+πΌ This rule is enabled in the following configs: β
`recommended`, π `strict`.
+
+π This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
+
+
+
+This rule forbids passing values that are not `Error` objects to `throwError`.
+It's similar to the typescript-eslint [`only-throw-error`](https://typescript-eslint.io/rules/only-throw-error/) rule,
+but is for the `throwError` Observable creation function - not `throw` statements.
## Rule details
Examples of **incorrect** code for this rule:
-```ts
-throw "Kaboom!";
-```
-
```ts
import { throwError } from "rxjs";
-throwError("Kaboom!");
-```
-```ts
-import { throwError } from "rxjs";
throwError(() => "Kaboom!");
```
Examples of **correct** code for this rule:
-```ts
-throw new Error("Kaboom!");
-```
-
-```ts
-throw new RangeError("Kaboom!");
-```
-
-```ts
-throw new DOMException("Kaboom!");
-```
-
```ts
import { throwError } from "rxjs";
-throwError(new Error("Kaboom!"));
-```
-```ts
-import { throwError } from "rxjs";
throwError(() => new Error("Kaboom!"));
```
## Options
-This rule has no options.
\ No newline at end of file
+
+
+| Name | Description | Type | Default |
+| :--------------------- | :---------------------------------------------------------- | :------ | :------ |
+| `allowThrowingAny` | Whether to always allow throwing values typed as `any`. | Boolean | `true` |
+| `allowThrowingUnknown` | Whether to always allow throwing values typed as `unknown`. | Boolean | `true` |
+
+
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..3eec6b1d
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,108 @@
+// @ts-check
+import js from '@eslint/js';
+import stylistic from '@stylistic/eslint-plugin';
+import gitignore from 'eslint-config-flat-gitignore';
+import importX from 'eslint-plugin-import-x';
+import n from 'eslint-plugin-n';
+import tseslint from 'typescript-eslint';
+import vitest from '@vitest/eslint-plugin';
+import eslintPlugin from 'eslint-plugin-eslint-plugin';
+
+/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.Config} */
+// @ts-expect-error -- eslint-plugin does not provide types.
+const eslintPluginConfig = eslintPlugin.configs['flat/recommended'];
+
+export default tseslint.config(gitignore(), {
+ files: [
+ 'src/**/*.ts',
+ 'tests/**/*.ts',
+ ],
+ extends: [
+ js.configs.recommended,
+ ...tseslint.configs.strictTypeChecked,
+ ...tseslint.configs.stylisticTypeChecked,
+ stylistic.configs['disable-legacy'],
+ stylistic.configs.customize({
+ flat: true,
+ quotes: 'single',
+ indent: 2,
+ semi: true,
+ jsx: false,
+ braceStyle: '1tbs',
+ commaDangle: 'always-multiline',
+ }),
+ n.configs['flat/recommended-module'],
+ importX.flatConfigs.recommended,
+ importX.flatConfigs.typescript,
+ eslintPluginConfig,
+ ],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ },
+ },
+ rules: {
+ '@stylistic/arrow-parens': 'off',
+ '@stylistic/multiline-ternary': 'off',
+
+ 'sort-imports': [
+ 'warn',
+ {
+ ignoreCase: true,
+ ignoreDeclarationSort: true,
+ },
+ ],
+ 'import-x/order': [
+ 'warn',
+ {
+ alphabetize: {
+ order: 'asc',
+ orderImportKind: 'asc',
+ caseInsensitive: true,
+ },
+ },
+ ],
+
+ 'import-x/no-named-as-default-member': 'off',
+
+ 'n/no-missing-import': 'off',
+
+ 'eslint-plugin/require-meta-docs-description': [
+ 'error',
+ {
+ pattern: '^(Enforce|Require|Disallow)',
+ },
+ ],
+ 'eslint-plugin/prefer-placeholders': 'error',
+ 'eslint-plugin/require-meta-schema-description': 'error',
+
+ '@typescript-eslint/no-unnecessary-condition': 'off',
+ '@typescript-eslint/restrict-template-expressions': [
+ 'error',
+ {
+ allowNumber: true,
+ allowBoolean: true,
+ allowAny: true,
+ allowNullish: true,
+ allowRegExp: true,
+ allowNever: true,
+ },
+ ],
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ {
+ vars: 'all',
+ varsIgnorePattern: '^_',
+ args: 'after-used',
+ argsIgnorePattern: '^_',
+ },
+ ],
+ },
+}, {
+ files: [
+ 'tests/**/*.ts',
+ ],
+ extends: [
+ vitest.configs.recommended,
+ ],
+});
diff --git a/package.json b/package.json
index 304e143b..d180afec 100644
--- a/package.json
+++ b/package.json
@@ -1,82 +1,102 @@
{
- "author": "Nicholas Jamieson ",
- "bugs": {
- "url": "https://github.com/cartant/eslint-plugin-rxjs/issues"
- },
- "dependencies": {
- "@typescript-eslint/experimental-utils": "^5.0.0",
- "common-tags": "^1.8.0",
- "decamelize": "^5.0.0",
- "eslint-etc": "^5.1.0",
- "requireindex": "~1.2.0",
- "rxjs-report-usage": "^1.0.4",
- "tslib": "^2.0.0",
- "tsutils": "^3.0.0",
- "tsutils-etc": "^1.4.1"
+ "name": "eslint-plugin-rxjs-x",
+ "type": "commonjs",
+ "version": "0.5.1",
+ "packageManager": "yarn@4.5.3+sha512.3003a14012e2987072d244c720506549c1aab73ee728208f1b2580a9fd67b92d61ba6b08fe93f6dce68fd771e3af1e59a0afa28dd242dd0940d73b95fedd4e90",
+ "description": "ESLint v9+ plugin for RxJS",
+ "author": "Jason Weinzierl ",
+ "license": "MIT",
+ "homepage": "https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x.git"
},
- "description": "ESLint rules for RxJS",
- "devDependencies": {
- "@cartant/eslint-config": "^3.0.0",
- "@types/chai": "^4.2.0",
- "@types/common-tags": "^1.8.0",
- "@types/eslint": "^8.0.0",
- "@types/mocha": "^9.0.0",
- "@types/node": "^18.0.0",
- "@typescript-eslint/parser": "^5.0.0",
- "chai": "^4.2.0",
- "eslint": "^8.0.0",
- "husky": "^8.0.0",
- "lint-staged": "^13.0.0",
- "mocha": "^9.0.0",
- "prettier": "^2.0.0",
- "rimraf": "^3.0.0",
- "rxjs": "^7.0.0",
- "ts-node": "^10.0.0",
- "typescript": "~4.7.4"
+ "bugs": {
+ "url": "https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/issues"
},
- "files": [
- "dist",
- "docs"
- ],
- "homepage": "https://github.com/cartant/eslint-plugin-rxjs",
"keywords": [
"lint",
"rules",
"eslint",
+ "eslintplugin",
+ "eslint-plugin",
"rxjs"
],
- "license": "MIT",
- "lint-staged": {
- "*.{js,ts}": "prettier --write"
+ "sideEffects": false,
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.mts",
+ "default": "./dist/index.mjs"
+ },
+ "require": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ }
+ }
},
"main": "./dist/index.js",
- "name": "eslint-plugin-rxjs",
- "optionalDependencies": {},
- "peerDependencies": {
- "eslint": "^8.0.0",
- "typescript": ">=4.0.0"
+ "module": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
+ "files": [
+ "dist",
+ "docs"
+ ],
+ "scripts": {
+ "build": "tsup",
+ "lint": "yarn lint-js && yarn lint-docs && yarn lint-eslint-docs",
+ "lint-js": "eslint",
+ "lint-docs": "markdownlint-cli2 \"**/*.md\" \"#node_modules\"",
+ "lint-eslint-docs": "yarn build && eslint-doc-generator --check",
+ "docs": "eslint-doc-generator",
+ "release": "bumpp && echo \"Create a new release in GitHub to trigger the publish workflow.\"",
+ "test": "vitest",
+ "coverage": "vitest run --coverage",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "^8.1.0",
+ "@typescript-eslint/utils": "^8.1.0",
+ "common-tags": "^1.8.0",
+ "decamelize": "^5.0.1",
+ "ts-api-utils": "^1.3.0",
+ "tslib": "^2.1.0"
},
- "private": false,
- "publishConfig": {
- "tag": "latest"
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "rxjs": ">=7.2.0",
+ "typescript": ">=4.7.4"
},
- "repository": {
- "type": "git",
- "url": "https://github.com/cartant/eslint-plugin-rxjs.git"
+ "peerDependenciesMeta": {
+ "rxjs": {
+ "optional": true
+ }
},
- "scripts": {
- "dist": "yarn run lint && yarn run dist:build",
- "dist:build": "yarn run dist:clean && tsc -p tsconfig-dist.json",
- "dist:clean": "rimraf dist",
- "lint": "eslint source/**/*.ts tests/**/*.ts",
- "prepare": "husky install",
- "prepublishOnly": "yarn run test && yarn run dist",
- "prettier": "prettier --write \"./{src,tests}/**/*.{js,json,ts,tsx}\"",
- "prettier:ci": "prettier --check \"./{src,tests}/**/*.{js,json,ts,tsx}\"",
- "test": "yarn run test:rules && yarn run test:specs",
- "test:debug": "mocha -r ts-node/register -t 5000 tests/rules/no-redundant-notify.ts",
- "test:rules": "mocha -r ts-node/register -t 5000 tests/rules/*.ts",
- "test:specs": "mocha -r ts-node/register tests/*-spec.ts"
+ "devDependencies": {
+ "@eslint/js": "^9.16.0",
+ "@stylistic/eslint-plugin": "^2.11.0",
+ "@types/common-tags": "^1.8.4",
+ "@types/node": "~18.18.0",
+ "@typescript-eslint/rule-tester": "^8.17.0",
+ "@typescript/vfs": "^1.6.0",
+ "@vitest/coverage-v8": "^2.1.8",
+ "@vitest/eslint-plugin": "^1.1.14",
+ "bumpp": "^9.8.1",
+ "eslint": "^9.16.0",
+ "eslint-config-flat-gitignore": "^0.3.0",
+ "eslint-doc-generator": "^1.7.1",
+ "eslint-import-resolver-typescript": "^3.6.3",
+ "eslint-plugin-eslint-plugin": "^6.3.2",
+ "eslint-plugin-import-x": "^4.4.2",
+ "eslint-plugin-n": "^17.14.0",
+ "markdownlint-cli2": "^0.15.0",
+ "rxjs": "^7.8.1",
+ "tsup": "^8.3.5",
+ "typescript": "~5.7.2",
+ "typescript-eslint": "^8.17.0",
+ "vitest": "^2.1.8"
},
- "version": "5.0.3"
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >= 21.1.0"
+ }
}
diff --git a/source/configs/recommended.ts b/source/configs/recommended.ts
deleted file mode 100644
index 606fd7b3..00000000
--- a/source/configs/recommended.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-export = {
- plugins: ["rxjs"],
- rules: {
- "rxjs/no-async-subscribe": "error",
- "rxjs/no-create": "error",
- "rxjs/no-ignored-notifier": "error",
- "rxjs/no-ignored-replay-buffer": "error",
- "rxjs/no-ignored-takewhile-value": "error",
- "rxjs/no-implicit-any-catch": "error",
- "rxjs/no-index": "error",
- "rxjs/no-internal": "error",
- "rxjs/no-nested-subscribe": "error",
- "rxjs/no-redundant-notify": "error",
- "rxjs/no-sharereplay": ["error", { allowConfig: true }],
- "rxjs/no-subject-unsubscribe": "error",
- "rxjs/no-unbound-methods": "error",
- "rxjs/no-unsafe-subject-next": "error",
- "rxjs/no-unsafe-takeuntil": "error",
- },
-};
diff --git a/source/constants.ts b/source/constants.ts
deleted file mode 100644
index fa233fe3..00000000
--- a/source/constants.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-export const defaultObservable = String.raw`[Aa]ction(s|s\$|\$)$`;
diff --git a/source/index.ts b/source/index.ts
deleted file mode 100644
index c88c99e2..00000000
--- a/source/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-module.exports.configs = require("requireindex")(`${__dirname}/configs`);
-module.exports.rules = require("requireindex")(`${__dirname}/rules`);
diff --git a/source/rules/ban-operators.ts b/source/rules/ban-operators.ts
deleted file mode 100644
index 4512b2db..00000000
--- a/source/rules/ban-operators.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import { ruleCreator } from "../utils";
-
-const defaultOptions: readonly Record[] = [];
-
-const rule = ruleCreator({
- defaultOptions,
- meta: {
- docs: {
- description: "Forbids the use of banned operators.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "RxJS operator is banned: {{name}}{{explanation}}.",
- },
- schema: [
- {
- type: "object",
- description: stripIndent`
- An object containing keys that are names of operators
- and values that are either booleans or strings containing the explanation for the ban.`,
- },
- ],
- type: "problem",
- },
- name: "ban-operators",
- create: (context, unused: typeof defaultOptions) => {
- let bans: { explanation: string; regExp: RegExp }[] = [];
-
- const [config] = context.options;
- if (!config) {
- return {};
- }
-
- Object.entries(config).forEach(([key, value]) => {
- if (value !== false) {
- bans.push({
- explanation: typeof value === "string" ? value : "",
- regExp: new RegExp(`^${key}$`),
- });
- }
- });
-
- function getFailure(name: string) {
- for (let b = 0, length = bans.length; b < length; ++b) {
- const ban = bans[b];
- if (ban.regExp.test(name)) {
- const explanation = ban.explanation ? `: ${ban.explanation}` : "";
- return {
- messageId: "forbidden",
- data: { name, explanation },
- } as const;
- }
- }
- return undefined;
- }
-
- return {
- [String.raw`ImportDeclaration[source.value=/^rxjs\u002foperators$/] > ImportSpecifier`]:
- (node: es.ImportSpecifier) => {
- const identifier = node.imported;
- const failure = getFailure(identifier.name);
- if (failure) {
- context.report({
- ...failure,
- node: identifier,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/just.ts b/source/rules/just.ts
deleted file mode 100644
index eb804731..00000000
--- a/source/rules/just.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Enforces the use of a `just` alias for `of`.",
- recommended: false,
- },
- fixable: "code",
- hasSuggestions: false,
- messages: {
- forbidden: "Use just alias.",
- },
- schema: [],
- type: "problem",
- },
- name: "just",
- create: (context) => {
- return {
- "ImportDeclaration[source.value='rxjs'] > ImportSpecifier[imported.name='of']":
- (node: es.ImportSpecifier) => {
- // import declaration has been renamed
- if (
- node.local.range[0] !== node.imported.range[0] &&
- node.local.range[1] !== node.imported.range[1]
- ) {
- return;
- }
-
- context.report({
- messageId: "forbidden",
- node,
- fix: (fixer) => fixer.replaceTextRange(node.range, "of as just"),
- });
-
- const [ofImport] = context.getDeclaredVariables(node);
- ofImport.references.forEach((ref) => {
- context.report({
- messageId: "forbidden",
- node: ref.identifier,
- fix: (fixer) =>
- fixer.replaceTextRange(ref.identifier.range, "just"),
- });
- });
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-async-subscribe.ts b/source/rules/no-async-subscribe.ts
deleted file mode 100644
index d2d18884..00000000
--- a/source/rules/no-async-subscribe.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids passing `async` functions to `subscribe`.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Passing async functions to subscribe is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-async-subscribe",
- create: (context) => {
- const { couldBeObservable } = getTypeServices(context);
-
- function checkNode(
- node: es.FunctionExpression | es.ArrowFunctionExpression
- ) {
- const parentNode = getParent(node) as es.CallExpression;
- const callee = parentNode.callee as es.MemberExpression;
-
- if (couldBeObservable(callee.object)) {
- const { loc } = node;
- // only report the `async` keyword
- const asyncLoc = {
- ...loc,
- end: {
- ...loc.start,
- column: loc.start.column + 5,
- },
- };
-
- context.report({
- messageId: "forbidden",
- loc: asyncLoc,
- });
- }
- }
- return {
- "CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]":
- checkNode,
- "CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]":
- checkNode,
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-compat.ts b/source/rules/no-compat.ts
deleted file mode 100644
index 2310d707..00000000
--- a/source/rules/no-compat.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids importation from locations that depend upon `rxjs-compat`.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "'rxjs-compat'-dependent import locations are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-compat",
- create: (context) => {
- return {
- [String.raw`ImportDeclaration Literal[value=/^rxjs\u002f/]:not(Literal[value=/^rxjs\u002f(ajax|fetch|operators|testing|webSocket)/])`]:
- (node: es.Literal) => {
- context.report({
- messageId: "forbidden",
- node,
- });
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-connectable.ts b/source/rules/no-connectable.ts
deleted file mode 100644
index 77289cb7..00000000
--- a/source/rules/no-connectable.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids operators that return connectable observables.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Connectable observables are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-connectable",
- create: (context) => {
- const { couldBeFunction } = getTypeServices(context);
- return {
- "CallExpression[callee.name='multicast']": (node: es.CallExpression) => {
- if (node.arguments.length === 1) {
- context.report({
- messageId: "forbidden",
- node: node.callee,
- });
- }
- },
- "CallExpression[callee.name=/^(publish|publishBehavior|publishLast|publishReplay)$/]":
- (node: es.CallExpression) => {
- if (!node.arguments.some((arg) => couldBeFunction(arg))) {
- context.report({
- messageId: "forbidden",
- node: node.callee,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-create.ts b/source/rules/no-create.ts
deleted file mode 100644
index 47c51bba..00000000
--- a/source/rules/no-create.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the calling of `Observable.create`.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Observable.create is forbidden; use new Observable.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-create",
- create: (context) => {
- const { couldBeObservable } = getTypeServices(context);
-
- return {
- "CallExpression > MemberExpression[object.name='Observable'] > Identifier[name='create']":
- (node: es.Identifier) => {
- const memberExpression = getParent(node) as es.MemberExpression;
- if (couldBeObservable(memberExpression.object)) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-explicit-generics.ts b/source/rules/no-explicit-generics.ts
deleted file mode 100644
index 4f9ff4bf..00000000
--- a/source/rules/no-explicit-generics.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, isArrayExpression, isObjectExpression } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids explicit generic type arguments.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Explicit generic type arguments are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-explicit-generics",
- create: (context) => {
- function report(node: es.Node) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
-
- function checkBehaviorSubjects(node: es.Node) {
- const parent = getParent(node) as es.NewExpression;
- const {
- arguments: [value],
- } = parent;
- if (isArrayExpression(value) || isObjectExpression(value)) {
- return;
- }
- report(node);
- }
-
- function checkNotifications(node: es.Node) {
- const parent = getParent(node) as es.NewExpression;
- const {
- arguments: [, value],
- } = parent;
- if (isArrayExpression(value) || isObjectExpression(value)) {
- return;
- }
- report(node);
- }
-
- return {
- "CallExpression[callee.property.name='pipe'] > CallExpression[typeParameters.params.length > 0] > Identifier":
- report,
- "NewExpression[typeParameters.params.length > 0] > Identifier[name='BehaviorSubject']":
- checkBehaviorSubjects,
- "CallExpression[typeParameters.params.length > 0] > Identifier[name=/^(from|of)$/]":
- report,
- "NewExpression[typeParameters.params.length > 0][arguments.0.value='N'] > Identifier[name='Notification']":
- checkNotifications,
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-finnish.ts b/source/rules/no-finnish.ts
deleted file mode 100644
index 6f13a1a4..00000000
--- a/source/rules/no-finnish.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import {
- getLoc,
- getParent,
- getParserServices,
- getTypeServices,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the use of Finnish notation.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Finnish notation is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-finnish",
- create: (context) => {
- const { esTreeNodeToTSNodeMap } = getParserServices(context);
- const { couldBeObservable, couldReturnObservable } =
- getTypeServices(context);
-
- function checkNode(nameNode: es.Node, typeNode?: es.Node) {
- if (
- couldBeObservable(typeNode || nameNode) ||
- couldReturnObservable(typeNode || nameNode)
- ) {
- const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
- if (/[$]+$/.test(tsNode.getText())) {
- context.report({
- loc: getLoc(tsNode),
- messageId: "forbidden",
- });
- }
- }
- }
-
- return {
- "ArrayPattern > Identifier[name=/[$]+$/]": (node: es.Identifier) =>
- checkNode(node),
- "ArrowFunctionExpression > Identifier[name=/[$]+$/]": (
- node: es.Identifier
- ) => {
- const parent = getParent(node) as es.ArrowFunctionExpression;
- if (node !== parent.body) {
- checkNode(node);
- }
- },
- "PropertyDefinition[key.name=/[$]+$/] > Identifier": (
- node: es.Identifier
- ) => checkNode(node, getParent(node)),
- "FunctionDeclaration > Identifier[name=/[$]+$/]": (
- node: es.Identifier
- ) => {
- const parent = getParent(node) as es.FunctionDeclaration;
- if (node === parent.id) {
- checkNode(node, parent);
- } else {
- checkNode(node);
- }
- },
- "FunctionExpression > Identifier[name=/[$]+$/]": (
- node: es.Identifier
- ) => {
- const parent = getParent(node) as es.FunctionExpression;
- if (node === parent.id) {
- checkNode(node, parent);
- } else {
- checkNode(node);
- }
- },
- "MethodDefinition[key.name=/[$]+$/]": (node: es.MethodDefinition) =>
- checkNode(node.key, node),
- "ObjectExpression > Property[computed=false][key.name=/[$]+$/]": (
- node: es.Property
- ) => checkNode(node.key),
- "ObjectPattern > Property[value.name=/[$]+$/]": (node: es.Property) =>
- checkNode(node.value),
- "TSCallSignatureDeclaration > Identifier[name=/[$]+$/]": (
- node: es.Node
- ) => checkNode(node),
- "TSConstructSignatureDeclaration > Identifier[name=/[$]+$/]": (
- node: es.Node
- ) => checkNode(node),
- "TSParameterProperty > Identifier[name=/[$]+$/]": (node: es.Identifier) =>
- checkNode(node),
- "TSPropertySignature > Identifier[name=/[$]+$/]": (node: es.Identifier) =>
- checkNode(node, getParent(node)),
- "TSMethodSignature > Identifier[name=/[$]+$/]": (node: es.Identifier) => {
- const parent = getParent(node) as any;
- if (node === parent.key) {
- checkNode(node, parent);
- } else {
- checkNode(node);
- }
- },
- "VariableDeclarator[id.name=/[$]+$/]": (node: es.VariableDeclarator) =>
- checkNode(node.id, node.init ?? node),
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-error.ts b/source/rules/no-ignored-error.ts
deleted file mode 100644
index 6f0bf133..00000000
--- a/source/rules/no-ignored-error.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids the calling of `subscribe` without specifying an error handler.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Calling subscribe without an error handler is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-error",
- create: (context) => {
- const { couldBeObservable, couldBeFunction } = getTypeServices(context);
-
- return {
- "CallExpression[arguments.length > 0] > MemberExpression > Identifier[name='subscribe']":
- (node: es.Identifier) => {
- const memberExpression = getParent(node) as es.MemberExpression;
- const callExpression = getParent(
- memberExpression
- ) as es.CallExpression;
-
- if (
- callExpression.arguments.length < 2 &&
- couldBeObservable(memberExpression.object) &&
- couldBeFunction(callExpression.arguments[0])
- ) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-observable.ts b/source/rules/no-ignored-observable.ts
deleted file mode 100644
index e12c1749..00000000
--- a/source/rules/no-ignored-observable.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the ignoring of observables returned by functions.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Ignoring a returned Observable is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-observable",
- create: (context) => {
- const { couldBeObservable } = getTypeServices(context);
-
- return {
- "ExpressionStatement > CallExpression": (node: es.CallExpression) => {
- if (couldBeObservable(node)) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-replay-buffer.ts b/source/rules/no-ignored-replay-buffer.ts
deleted file mode 100644
index 1bb286ee..00000000
--- a/source/rules/no-ignored-replay-buffer.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Ignoring the buffer size is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-replay-buffer",
- create: (context) => {
- function checkNode(
- node: es.Node,
- { arguments: args }: { arguments: es.Node[] }
- ) {
- if (!args || args.length === 0) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- }
-
- return {
- "NewExpression > Identifier[name='ReplaySubject']": (
- node: es.Identifier
- ) => {
- const newExpression = getParent(node) as es.NewExpression;
- checkNode(node, newExpression);
- },
- "NewExpression > MemberExpression > Identifier[name='ReplaySubject']": (
- node: es.Identifier
- ) => {
- const memberExpression = getParent(node) as es.MemberExpression;
- const newExpression = getParent(memberExpression) as es.NewExpression;
- checkNode(node, newExpression);
- },
- "CallExpression > Identifier[name=/^(publishReplay|shareReplay)$/]": (
- node: es.Identifier
- ) => {
- const callExpression = getParent(node) as es.CallExpression;
- checkNode(node, callExpression);
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-subscribe.ts b/source/rules/no-ignored-subscribe.ts
deleted file mode 100644
index 302963b5..00000000
--- a/source/rules/no-ignored-subscribe.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids the calling of `subscribe` without specifying arguments.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Calling subscribe without arguments is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-subscribe",
- create: (context) => {
- const { couldBeObservable, couldBeType } = getTypeServices(context);
-
- return {
- "CallExpression[arguments.length = 0][callee.property.name='subscribe']":
- (node: es.CallExpression) => {
- const callee = node.callee as es.MemberExpression;
- if (
- couldBeObservable(callee.object) ||
- couldBeType(callee.object, "Subscribable")
- ) {
- context.report({
- messageId: "forbidden",
- node: callee.property,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-subscription.ts b/source/rules/no-ignored-subscription.ts
deleted file mode 100644
index a7871527..00000000
--- a/source/rules/no-ignored-subscription.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids ignoring the subscription returned by `subscribe`.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Ignoring returned subscriptions is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-subscription",
- create: (context) => {
- const { couldBeObservable, couldBeType } = getTypeServices(context);
-
- return {
- "ExpressionStatement > CallExpression > MemberExpression[property.name='subscribe']":
- (node: es.MemberExpression) => {
- if (couldBeObservable(node.object)) {
- const callExpression = getParent(node) as es.CallExpression;
- if (
- callExpression.arguments.length === 1 &&
- couldBeType(callExpression.arguments[0], "Subscriber")
- ) {
- return;
- }
- context.report({
- messageId: "forbidden",
- node: node.property,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-ignored-takewhile-value.ts b/source/rules/no-ignored-takewhile-value.ts
deleted file mode 100644
index 47662640..00000000
--- a/source/rules/no-ignored-takewhile-value.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import {
- isArrayPattern,
- isIdentifier,
- isImport,
- isObjectPattern,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids ignoring the value within `takeWhile`.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Ignoring the value within takeWhile is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-ignored-takewhile-value",
- create: (context) => {
- function checkNode(
- expression: es.ArrowFunctionExpression | es.FunctionExpression
- ) {
- const scope = context.getScope();
- if (!isImport(scope, "takeWhile", /^rxjs\/?/)) {
- return;
- }
- let ignored = true;
- const [param] = expression.params;
- if (param) {
- if (isIdentifier(param)) {
- const variable = scope.variables.find(
- ({ name }) => name === param.name
- );
- if (variable && variable.references.length > 0) {
- ignored = false;
- }
- } else if (isArrayPattern(param)) {
- ignored = false;
- } else if (isObjectPattern(param)) {
- ignored = false;
- }
- }
- if (ignored) {
- context.report({
- messageId: "forbidden",
- node: expression,
- });
- }
- }
-
- return {
- "CallExpression[callee.name='takeWhile'] > ArrowFunctionExpression": (
- node: es.ArrowFunctionExpression
- ) => checkNode(node),
- "CallExpression[callee.name='takeWhile'] > FunctionExpression": (
- node: es.FunctionExpression
- ) => checkNode(node),
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-index.ts b/source/rules/no-index.ts
deleted file mode 100644
index 8b3a31f5..00000000
--- a/source/rules/no-index.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the importation from index modules.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "RxJS imports from index modules are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-index",
- create: (context) => {
- return {
- [String.raw`ImportDeclaration Literal[value=/^rxjs(?:\u002f\w+)?\u002findex/]`]:
- (node: es.Literal) => {
- context.report({
- messageId: "forbidden",
- node,
- });
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-nested-subscribe.ts b/source/rules/no-nested-subscribe.ts
deleted file mode 100644
index 8af16cf4..00000000
--- a/source/rules/no-nested-subscribe.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids the calling of `subscribe` within a `subscribe` callback.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Nested subscribe calls are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-nested-subscribe",
- create: (context) => {
- const { couldBeObservable, couldBeType } = getTypeServices(context);
- const argumentsMap = new WeakMap();
- return {
- [`CallExpression > MemberExpression[property.name='subscribe']`]: (
- node: es.MemberExpression
- ) => {
- if (
- !couldBeObservable(node.object) &&
- !couldBeType(node.object, "Subscribable")
- ) {
- return;
- }
- const callExpression = getParent(node) as es.CallExpression;
- let parent = getParent(callExpression);
- while (parent) {
- if (argumentsMap.has(parent)) {
- context.report({
- messageId: "forbidden",
- node: node.property,
- });
- return;
- }
- parent = getParent(parent);
- }
- for (const arg of callExpression.arguments) {
- argumentsMap.set(arg);
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-sharereplay.ts b/source/rules/no-sharereplay.ts
deleted file mode 100644
index 25778eb6..00000000
--- a/source/rules/no-sharereplay.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
-
-const defaultOptions: readonly {
- allowConfig?: boolean;
-}[] = [];
-
-const rule = ruleCreator({
- defaultOptions,
- meta: {
- docs: {
- description: "Forbids using the `shareReplay` operator.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "shareReplay is forbidden.",
- forbiddenWithoutConfig:
- "shareReplay is forbidden unless a config argument is passed.",
- },
- schema: [
- {
- properties: {
- allowConfig: { type: "boolean" },
- },
- type: "object",
- },
- ],
- type: "problem",
- },
- name: "no-sharereplay",
- create: (context, unused: typeof defaultOptions) => {
- const [config = {}] = context.options;
- const { allowConfig = true } = config;
- return {
- "CallExpression[callee.name='shareReplay']": (
- node: es.CallExpression
- ) => {
- let report = true;
- if (allowConfig) {
- report =
- node.arguments.length !== 1 ||
- node.arguments[0].type !== "ObjectExpression";
- }
- if (report) {
- context.report({
- messageId: allowConfig ? "forbiddenWithoutConfig" : "forbidden",
- node: node.callee,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-subclass.ts b/source/rules/no-subclass.ts
deleted file mode 100644
index 16dfaeae..00000000
--- a/source/rules/no-subclass.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids subclassing RxJS classes.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Subclassing RxJS classes is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-subclass",
- create: (context) => {
- const { couldBeType } = getTypeServices(context);
-
- const queryNames = [
- "AsyncSubject",
- "BehaviorSubject",
- "Observable",
- "ReplaySubject",
- "Scheduler",
- "Subject",
- "Subscriber",
- ];
-
- return {
- [`ClassDeclaration[superClass.name=/^(${queryNames.join(
- "|"
- )})$/] > Identifier.superClass`]: (node: es.Identifier) => {
- if (
- queryNames.some((name) =>
- couldBeType(node, name, { name: /[\/\\]rxjs[\/\\]/ })
- )
- ) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-subject-unsubscribe.ts b/source/rules/no-subject-unsubscribe.ts
deleted file mode 100644
index 8ddc6b65..00000000
--- a/source/rules/no-subject-unsubscribe.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids calling the `unsubscribe` method of a subject instance.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Calling unsubscribe on a subject is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-subject-unsubscribe",
- create: (context) => {
- const { couldBeSubject, couldBeSubscription } = getTypeServices(context);
-
- return {
- "MemberExpression[property.name='unsubscribe']": (
- node: es.MemberExpression
- ) => {
- if (couldBeSubject(node.object)) {
- context.report({
- messageId: "forbidden",
- node: node.property,
- });
- }
- },
- "CallExpression[callee.property.name='add'][arguments.length > 0]": (
- node: es.CallExpression
- ) => {
- const memberExpression = node.callee as es.MemberExpression;
- if (couldBeSubscription(memberExpression.object)) {
- const [arg] = node.arguments;
- if (couldBeSubject(arg)) {
- context.report({
- messageId: "forbidden",
- node: arg,
- });
- }
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-subject-value.ts b/source/rules/no-subject-value.ts
deleted file mode 100644
index 0d4e4acb..00000000
--- a/source/rules/no-subject-value.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParent, getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Forbids accessing the `value` property of a `BehaviorSubject` instance.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden:
- "Accessing the value property of a BehaviorSubject is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-subject-value",
- create: (context) => {
- const { couldBeBehaviorSubject } = getTypeServices(context);
-
- return {
- "Identifier[name=/^(value|getValue)$/]": (node: es.Identifier) => {
- const parent = getParent(node);
-
- if (!parent || !("object" in parent)) {
- return;
- }
-
- if (couldBeBehaviorSubject(parent.object)) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-subscribe-handlers.ts b/source/rules/no-subscribe-handlers.ts
deleted file mode 100644
index a886b642..00000000
--- a/source/rules/no-subscribe-handlers.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the passing of handlers to `subscribe`.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Passing handlers to subscribe is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-subscribe-handlers",
- create: (context) => {
- const { couldBeObservable, couldBeType } = getTypeServices(context);
-
- return {
- "CallExpression[arguments.length > 0][callee.property.name='subscribe']":
- (node: es.CallExpression) => {
- const callee = node.callee as es.MemberExpression;
- if (
- couldBeObservable(callee.object) ||
- couldBeType(callee.object, "Subscribable")
- ) {
- context.report({
- messageId: "forbidden",
- node: callee.property,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-tap.ts b/source/rules/no-tap.ts
deleted file mode 100644
index 48c53dea..00000000
--- a/source/rules/no-tap.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- deprecated: true,
- docs: {
- description: "Forbids the use of the `tap` operator.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "The tap operator is forbidden.",
- },
- replacedBy: ["ban-operators"],
- schema: [],
- type: "problem",
- },
- name: "no-tap",
- create: (context) => {
- return {
- [String.raw`ImportDeclaration[source.value=/^rxjs(\u002foperators)?$/] > ImportSpecifier[imported.name='tap']`]:
- (node: es.ImportSpecifier) => {
- const { loc } = node;
- context.report({
- messageId: "forbidden",
- loc: {
- ...loc,
- end: {
- ...loc.start,
- column: loc.start.column + 3,
- },
- },
- });
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-topromise.ts b/source/rules/no-topromise.ts
deleted file mode 100644
index 1cdd5d2d..00000000
--- a/source/rules/no-topromise.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices } from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the use of the `toPromise` method.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "The toPromise method is forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-topromise",
- create: (context) => {
- const { couldBeObservable } = getTypeServices(context);
- return {
- [`MemberExpression[property.name="toPromise"]`]: (
- node: es.MemberExpression
- ) => {
- if (couldBeObservable(node.object)) {
- context.report({
- messageId: "forbidden",
- node: node.property,
- });
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-unbound-methods.ts b/source/rules/no-unbound-methods.ts
deleted file mode 100644
index 2f624cda..00000000
--- a/source/rules/no-unbound-methods.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import {
- getParent,
- getTypeServices,
- isCallExpression,
- isMemberExpression,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids the passing of unbound methods.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Unbound methods are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-unbound-methods",
- create: (context) => {
- const { couldBeObservable, couldBeSubscription, getType } =
- getTypeServices(context);
- const nodeMap = new WeakMap();
-
- function mapArguments(node: es.CallExpression | es.NewExpression) {
- node.arguments.filter(isMemberExpression).forEach((arg) => {
- const argType = getType(arg);
- if (argType.getCallSignatures().length > 0) {
- nodeMap.set(arg);
- }
- });
- }
-
- function isObservableOrSubscription(
- node: es.CallExpression,
- action: (node: es.CallExpression) => void
- ) {
- if (!isMemberExpression(node.callee)) {
- return;
- }
-
- if (
- couldBeObservable(node.callee.object) ||
- couldBeSubscription(node.callee.object)
- ) {
- action(node);
- }
- }
-
- return {
- "CallExpression[callee.property.name='pipe']": (
- node: es.CallExpression
- ) => {
- isObservableOrSubscription(node, ({ arguments: args }) => {
- args.filter(isCallExpression).forEach(mapArguments);
- });
- },
- "CallExpression[callee.property.name=/^(add|subscribe)$/]": (
- node: es.CallExpression
- ) => {
- isObservableOrSubscription(node, mapArguments);
- },
- "NewExpression[callee.name='Subscription']": mapArguments,
- ThisExpression: (node: es.ThisExpression) => {
- let parent = getParent(node);
- while (parent) {
- if (nodeMap.has(parent)) {
- context.report({
- messageId: "forbidden",
- node: parent,
- });
- return;
- }
- parent = getParent(parent);
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/no-unsafe-subject-next.ts b/source/rules/no-unsafe-subject-next.ts
deleted file mode 100644
index f829fcf7..00000000
--- a/source/rules/no-unsafe-subject-next.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import {
- getParserServices,
- getTypeServices,
- isMemberExpression,
-} from "eslint-etc";
-import * as tsutils from "tsutils";
-import { couldBeType, isReferenceType, isUnionType } from "tsutils-etc";
-import * as ts from "typescript";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description: "Forbids unsafe optional `next` calls.",
- recommended: "error",
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Unsafe optional next calls are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "no-unsafe-subject-next",
- create: (context) => {
- const { esTreeNodeToTSNodeMap } = getParserServices(context);
- const { typeChecker } = getTypeServices(context);
- return {
- [`CallExpression[callee.property.name='next']`]: (
- node: es.CallExpression
- ) => {
- if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
- const type = typeChecker.getTypeAtLocation(
- esTreeNodeToTSNodeMap.get(node.callee.object)
- );
- if (isReferenceType(type) && couldBeType(type, "Subject")) {
- const [typeArg] = typeChecker.getTypeArguments(type);
- if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Any)) {
- return;
- }
- if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Unknown)) {
- return;
- }
- if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Void)) {
- return;
- }
- if (
- isUnionType(typeArg) &&
- typeArg.types.some((t) =>
- tsutils.isTypeFlagSet(t, ts.TypeFlags.Void)
- )
- ) {
- return;
- }
- context.report({
- messageId: "forbidden",
- node: node.callee.property,
- });
- }
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/rules/throw-error.ts b/source/rules/throw-error.ts
deleted file mode 100644
index 32cc0dd8..00000000
--- a/source/rules/throw-error.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getParserServices, getTypeServices } from "eslint-etc";
-import { couldBeFunction, couldBeType, isAny, isUnknown } from "tsutils-etc";
-import * as ts from "typescript";
-import { ruleCreator } from "../utils";
-
-const rule = ruleCreator({
- defaultOptions: [],
- meta: {
- docs: {
- description:
- "Enforces the passing of `Error` values to error notifications.",
- recommended: false,
- },
- fixable: undefined,
- hasSuggestions: false,
- messages: {
- forbidden: "Passing non-Error values are forbidden.",
- },
- schema: [],
- type: "problem",
- },
- name: "throw-error",
- create: (context) => {
- const { esTreeNodeToTSNodeMap, program } = getParserServices(context);
- const { couldBeObservable, getType } = getTypeServices(context);
-
- function checkNode(node: es.Node) {
- let type = getType(node);
- if (couldBeFunction(type)) {
- const tsNode = esTreeNodeToTSNodeMap.get(node);
- const annotation = (tsNode as ts.ArrowFunction).type;
- const body = (tsNode as ts.ArrowFunction).body;
- type = program.getTypeChecker().getTypeAtLocation(annotation ?? body);
- }
- if (
- !isAny(type) &&
- !isUnknown(type) &&
- !couldBeType(type, /^(Error|DOMException)$/)
- ) {
- context.report({
- messageId: "forbidden",
- node,
- });
- }
- }
-
- return {
- "ThrowStatement > *": checkNode,
- "CallExpression[callee.name='throwError']": (node: es.CallExpression) => {
- if (couldBeObservable(node)) {
- const [arg] = node.arguments;
- if (arg) {
- checkNode(arg);
- }
- }
- },
- };
- },
-});
-
-export = rule;
diff --git a/source/utils.ts b/source/utils.ts
deleted file mode 100644
index 30d85894..00000000
--- a/source/utils.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { ESLintUtils } from "@typescript-eslint/experimental-utils";
-
-export function createRegExpForWords(
- config: string | string[]
-): RegExp | undefined {
- if (!config || !config.length) {
- return undefined;
- }
- const flags = "i";
- if (typeof config === "string") {
- return new RegExp(config, flags);
- }
- const words = config;
- const joined = words.map((word) => String.raw`(\b|_)${word}(\b|_)`).join("|");
- return new RegExp(`(${joined})`, flags);
-}
-
-export function escapeRegExp(text: string): string {
- // https://stackoverflow.com/a/3561711/6680611
- return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
-}
-
-export const ruleCreator = ESLintUtils.RuleCreator(
- (name) =>
- `https://github.com/cartant/eslint-plugin-rxjs/tree/main/docs/rules/${name}.md`
-);
diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts
new file mode 100644
index 00000000..5d08cb94
--- /dev/null
+++ b/src/configs/recommended.ts
@@ -0,0 +1,32 @@
+import { TSESLint } from '@typescript-eslint/utils';
+
+export const createRecommendedConfig = (
+ plugin: TSESLint.FlatConfig.Plugin,
+) => ({
+ name: 'rxjs-x/recommended' as const,
+ plugins: {
+ 'rxjs-x': plugin,
+ },
+ rules: {
+ 'rxjs-x/no-async-subscribe': 'error',
+ 'rxjs-x/no-create': 'error',
+ 'rxjs-x/no-ignored-notifier': 'error',
+ 'rxjs-x/no-ignored-replay-buffer': 'error',
+ 'rxjs-x/no-ignored-takewhile-value': 'error',
+ 'rxjs-x/no-implicit-any-catch': 'error',
+ 'rxjs-x/no-index': 'error',
+ 'rxjs-x/no-internal': 'error',
+ 'rxjs-x/no-nested-subscribe': 'error',
+ 'rxjs-x/no-redundant-notify': 'error',
+ 'rxjs-x/no-sharereplay': 'error',
+ 'rxjs-x/no-subject-unsubscribe': 'error',
+ 'rxjs-x/no-subscribe-in-pipe': 'error',
+ 'rxjs-x/no-topromise': 'error',
+ 'rxjs-x/no-unbound-methods': 'error',
+ 'rxjs-x/no-unsafe-subject-next': 'error',
+ 'rxjs-x/no-unsafe-takeuntil': 'error',
+ 'rxjs-x/prefer-observer': 'error',
+ 'rxjs-x/prefer-root-operators': 'error',
+ 'rxjs-x/throw-error': 'error',
+ },
+} satisfies TSESLint.FlatConfig.Config);
diff --git a/src/configs/strict.ts b/src/configs/strict.ts
new file mode 100644
index 00000000..259ca297
--- /dev/null
+++ b/src/configs/strict.ts
@@ -0,0 +1,44 @@
+import { TSESLint } from '@typescript-eslint/utils';
+
+export const createStrictConfig = (
+ plugin: TSESLint.FlatConfig.Plugin,
+) => ({
+ name: 'rxjs-x/strict' as const,
+ plugins: {
+ 'rxjs-x': plugin,
+ },
+ rules: {
+ 'rxjs-x/no-async-subscribe': 'error',
+ 'rxjs-x/no-create': 'error',
+ 'rxjs-x/no-explicit-generics': 'error',
+ 'rxjs-x/no-exposed-subjects': 'error',
+ 'rxjs-x/no-floating-observables': 'error',
+ 'rxjs-x/no-ignored-default-value': 'error',
+ 'rxjs-x/no-ignored-error': 'error',
+ 'rxjs-x/no-ignored-notifier': 'error',
+ 'rxjs-x/no-ignored-replay-buffer': 'error',
+ 'rxjs-x/no-ignored-takewhile-value': 'error',
+ 'rxjs-x/no-implicit-any-catch': ['error', {
+ allowExplicitAny: false as const,
+ }],
+ 'rxjs-x/no-index': 'error',
+ 'rxjs-x/no-internal': 'error',
+ 'rxjs-x/no-misused-observables': 'error',
+ 'rxjs-x/no-nested-subscribe': 'error',
+ 'rxjs-x/no-redundant-notify': 'error',
+ 'rxjs-x/no-sharereplay': 'error',
+ 'rxjs-x/no-subclass': 'error',
+ 'rxjs-x/no-subject-unsubscribe': 'error',
+ 'rxjs-x/no-subscribe-in-pipe': 'error',
+ 'rxjs-x/no-topromise': 'error',
+ 'rxjs-x/no-unbound-methods': 'error',
+ 'rxjs-x/no-unsafe-subject-next': 'error',
+ 'rxjs-x/no-unsafe-takeuntil': 'error',
+ 'rxjs-x/prefer-observer': 'error',
+ 'rxjs-x/prefer-root-operators': 'error',
+ 'rxjs-x/throw-error': ['error', {
+ allowThrowingAny: false as const,
+ allowThrowingUnknown: false as const,
+ }],
+ },
+} satisfies TSESLint.FlatConfig.Config);
diff --git a/src/constants.ts b/src/constants.ts
new file mode 100644
index 00000000..7c9aa060
--- /dev/null
+++ b/src/constants.ts
@@ -0,0 +1 @@
+export const defaultObservable = String.raw`[Aa]ction(s|s\$|\$)$`;
diff --git a/src/etc/could-be-function.ts b/src/etc/could-be-function.ts
new file mode 100644
index 00000000..0a5e3c67
--- /dev/null
+++ b/src/etc/could-be-function.ts
@@ -0,0 +1,11 @@
+import ts from 'typescript';
+import { couldBeType } from './could-be-type';
+
+export function couldBeFunction(type: ts.Type): boolean {
+ return (
+ type.getCallSignatures().length > 0
+ || couldBeType(type, 'Function')
+ || couldBeType(type, 'ArrowFunction')
+ || couldBeType(type, ts.InternalSymbolName.Function)
+ );
+}
diff --git a/src/etc/could-be-type.ts b/src/etc/could-be-type.ts
new file mode 100644
index 00000000..b8156cce
--- /dev/null
+++ b/src/etc/could-be-type.ts
@@ -0,0 +1,110 @@
+import * as tsutils from 'ts-api-utils';
+import ts from 'typescript';
+
+export function couldBeType(
+ type: ts.Type,
+ name: string | RegExp,
+ qualified?: {
+ name: RegExp;
+ typeChecker: ts.TypeChecker;
+ },
+): boolean {
+ if (tsutils.isTypeReference(type)) {
+ type = type.target;
+ }
+
+ if (isType(type, name, qualified)) {
+ return true;
+ }
+
+ if (tsutils.isUnionOrIntersectionType(type)) {
+ return type.types.some(t => couldBeType(t, name, qualified));
+ }
+
+ const baseTypes = type.getBaseTypes();
+ if (baseTypes?.some(t => couldBeType(t, name, qualified))) {
+ return true;
+ }
+
+ if (couldImplement(type, name, qualified)) {
+ return true;
+ }
+
+ return false;
+}
+
+function isType(
+ type: ts.Type,
+ name: string | RegExp,
+ qualified?: {
+ name: RegExp;
+ typeChecker: ts.TypeChecker;
+ },
+): boolean {
+ if (!type.symbol) {
+ return false;
+ }
+ if (
+ qualified
+ && !qualified.name.test(
+ qualified.typeChecker.getFullyQualifiedName(type.symbol),
+ )
+ ) {
+ return false;
+ }
+ return typeof name === 'string'
+ ? type.symbol.name === name
+ : Boolean(type.symbol.name.match(name));
+}
+
+function couldImplement(
+ type: ts.Type,
+ name: string | RegExp,
+ qualified?: {
+ name: RegExp;
+ typeChecker: ts.TypeChecker;
+ },
+): boolean {
+ const { symbol } = type;
+ if (symbol) {
+ const { valueDeclaration } = symbol;
+ if (valueDeclaration && ts.isClassDeclaration(valueDeclaration)) {
+ const { heritageClauses } = valueDeclaration;
+ if (heritageClauses) {
+ const implemented = heritageClauses.some(
+ ({ token, types }) =>
+ token === ts.SyntaxKind.ImplementsKeyword
+ && types.some(node => isMatchingNode(node, name, qualified)),
+ );
+ if (implemented) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+function isMatchingNode(
+ node: ts.ExpressionWithTypeArguments,
+ name: string | RegExp,
+ qualified?: {
+ name: RegExp;
+ typeChecker: ts.TypeChecker;
+ },
+): boolean {
+ const { expression } = node;
+ if (qualified) {
+ const type = qualified.typeChecker.getTypeAtLocation(expression);
+ if (type) {
+ const qualifiedName = qualified.typeChecker.getFullyQualifiedName(
+ type.symbol,
+ );
+ if (!qualified.name.test(qualifiedName)) {
+ return false;
+ }
+ }
+ }
+ const text = expression.getText();
+ return typeof name === 'string' ? text === name : Boolean(text.match(name));
+}
diff --git a/src/etc/find-parent.ts b/src/etc/find-parent.ts
new file mode 100644
index 00000000..a9cac53f
--- /dev/null
+++ b/src/etc/find-parent.ts
@@ -0,0 +1,26 @@
+import { TSESTree } from '@typescript-eslint/utils';
+
+type Predicate = (type: string) => 'break' | 'continue' | 'return';
+
+export function findParent(node: TSESTree.Node, ...types: string[]): TSESTree.Node | undefined;
+export function findParent(node: TSESTree.Node, predicate: Predicate): TSESTree.Node | undefined;
+export function findParent(node: TSESTree.Node, ...args: (string | Predicate)[]): TSESTree.Node | undefined {
+ const [arg] = args;
+ const predicate: Predicate
+ = typeof arg === 'function'
+ ? arg
+ : (type: string) => (!args.includes(type) ? 'continue' : 'return');
+ let parent = node.parent as TSESTree.Node | undefined;
+ while (parent) {
+ switch (predicate(parent.type)) {
+ case 'break':
+ return undefined;
+ case 'return':
+ return parent;
+ default:
+ break;
+ }
+ parent = parent.parent;
+ }
+ return undefined;
+}
diff --git a/src/etc/get-loc.ts b/src/etc/get-loc.ts
new file mode 100644
index 00000000..68605a40
--- /dev/null
+++ b/src/etc/get-loc.ts
@@ -0,0 +1,18 @@
+import { TSESTree } from '@typescript-eslint/utils';
+import ts from 'typescript';
+
+export function getLoc(node: ts.Node): TSESTree.SourceLocation {
+ const sourceFile = node.getSourceFile();
+ const start = ts.getLineAndCharacterOfPosition(sourceFile, node.getStart());
+ const end = ts.getLineAndCharacterOfPosition(sourceFile, node.getEnd());
+ return {
+ start: {
+ line: start.line + 1,
+ column: start.character,
+ },
+ end: {
+ line: end.line + 1,
+ column: end.character,
+ },
+ };
+}
diff --git a/src/etc/get-type-services.ts b/src/etc/get-type-services.ts
new file mode 100644
index 00000000..5f38ba6c
--- /dev/null
+++ b/src/etc/get-type-services.ts
@@ -0,0 +1,81 @@
+import { ESLintUtils, TSESLint, TSESTree } from '@typescript-eslint/utils';
+import ts from 'typescript';
+import { couldBeFunction } from './could-be-function';
+import { couldBeType as tsutilsEtcCouldBeType } from './could-be-type';
+import { isArrowFunctionExpression, isFunctionDeclaration } from './is';
+
+export function getTypeServices<
+ TMessageIds extends string,
+ TOptions extends readonly unknown[],
+>(context: TSESLint.RuleContext>) {
+ const services = ESLintUtils.getParserServices(context);
+ const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = services;
+ const typeChecker = program.getTypeChecker();
+
+ const couldBeType = (
+ node: TSESTree.Node,
+ name: string | RegExp,
+ qualified?: { name: RegExp },
+ ): boolean => {
+ const type = getTypeAtLocation(node);
+ return tsutilsEtcCouldBeType(
+ type,
+ name,
+ qualified ? { ...qualified, typeChecker } : undefined,
+ );
+ };
+
+ const couldReturnType = (
+ node: TSESTree.Node,
+ name: string | RegExp,
+ qualified?: { name: RegExp },
+ ): boolean => {
+ let tsTypeNode: ts.Node | undefined;
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ if (
+ ts.isArrowFunction(tsNode)
+ || ts.isFunctionDeclaration(tsNode)
+ || ts.isMethodDeclaration(tsNode)
+ || ts.isFunctionExpression(tsNode)
+ ) {
+ tsTypeNode = tsNode.type ?? tsNode.body; // TODO(#57): this doesn't work for Block bodies.
+ } else if (
+ ts.isCallSignatureDeclaration(tsNode)
+ || ts.isMethodSignature(tsNode)
+ ) {
+ tsTypeNode = tsNode.type;
+ } else if (
+ ts.isPropertySignature(tsNode)
+ ) {
+ // TODO(#66): this doesn't work for functions assigned to class properties, variables, params.
+ }
+ return Boolean(
+ tsTypeNode
+ && tsutilsEtcCouldBeType(
+ typeChecker.getTypeAtLocation(tsTypeNode),
+ name,
+ qualified ? { ...qualified, typeChecker } : undefined,
+ ),
+ );
+ };
+
+ return {
+ couldBeBehaviorSubject: (node: TSESTree.Node) =>
+ couldBeType(node, 'BehaviorSubject'),
+ couldBeFunction: (node: TSESTree.Node) => {
+ if (isArrowFunctionExpression(node) || isFunctionDeclaration(node)) {
+ return true;
+ }
+ return couldBeFunction(getTypeAtLocation(node));
+ },
+ couldBeMonoTypeOperatorFunction: (node: TSESTree.Node) =>
+ couldBeType(node, 'MonoTypeOperatorFunction'),
+ couldBeObservable: (node: TSESTree.Node) => couldBeType(node, 'Observable'),
+ couldBeSubject: (node: TSESTree.Node) => couldBeType(node, 'Subject'),
+ couldBeSubscription: (node: TSESTree.Node) => couldBeType(node, 'Subscription'),
+ couldBeType,
+ couldReturnObservable: (node: TSESTree.Node) =>
+ couldReturnType(node, 'Observable'),
+ couldReturnType,
+ };
+}
diff --git a/src/etc/index.ts b/src/etc/index.ts
new file mode 100644
index 00000000..d66808aa
--- /dev/null
+++ b/src/etc/index.ts
@@ -0,0 +1,7 @@
+export * from './could-be-function';
+export * from './could-be-type';
+export * from './find-parent';
+export * from './get-loc';
+export * from './get-type-services';
+export * from './is-import';
+export * from './is';
diff --git a/src/etc/is-import.ts b/src/etc/is-import.ts
new file mode 100644
index 00000000..4de1b153
--- /dev/null
+++ b/src/etc/is-import.ts
@@ -0,0 +1,21 @@
+import { DefinitionType } from '@typescript-eslint/scope-manager';
+import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils';
+
+export function isImport(
+ scope: TSESLint.Scope.Scope,
+ name: string,
+ source: string | RegExp,
+): boolean {
+ const variable = scope.variables.find((variable) => variable.name === name);
+ if (variable) {
+ return variable.defs.some(
+ (def) =>
+ def.type === DefinitionType.ImportBinding
+ && def.parent.type === AST_NODE_TYPES.ImportDeclaration
+ && (typeof source === 'string'
+ ? def.parent.source.value === source
+ : source.test(def.parent.source.value)),
+ );
+ }
+ return scope.upper ? isImport(scope.upper, name, source) : false;
+}
diff --git a/src/etc/is.ts b/src/etc/is.ts
new file mode 100644
index 00000000..1bbaca16
--- /dev/null
+++ b/src/etc/is.ts
@@ -0,0 +1,151 @@
+import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
+
+export function hasTypeAnnotation(
+ node: T,
+): node is T & { typeAnnotation: TSESTree.TSTypeAnnotation } {
+ return 'typeAnnotation' in node && !!node.typeAnnotation;
+}
+
+export function isArrayExpression(node: TSESTree.Node): node is TSESTree.ArrayExpression {
+ return node.type === AST_NODE_TYPES.ArrayExpression;
+}
+
+export function isArrayPattern(node: TSESTree.Node): node is TSESTree.ArrayPattern {
+ return node.type === AST_NODE_TYPES.ArrayPattern;
+}
+
+export function isArrowFunctionExpression(
+ node: TSESTree.Node,
+): node is TSESTree.ArrowFunctionExpression {
+ return node.type === AST_NODE_TYPES.ArrowFunctionExpression;
+}
+
+export function isAssignmentExpression(
+ node: TSESTree.Node,
+): node is TSESTree.AssignmentExpression {
+ return node.type === AST_NODE_TYPES.AssignmentExpression;
+}
+
+export function isBlockStatement(node: TSESTree.Node): node is TSESTree.BlockStatement {
+ return node.type === AST_NODE_TYPES.BlockStatement;
+}
+
+export function isCallExpression(node: TSESTree.Node): node is TSESTree.CallExpression {
+ return node.type === AST_NODE_TYPES.CallExpression;
+}
+
+export function isChainExpression(node: TSESTree.Node): node is TSESTree.ChainExpression {
+ return node.type === AST_NODE_TYPES.ChainExpression;
+}
+
+export function isExportNamedDeclaration(
+ node: TSESTree.Node,
+): node is TSESTree.ExportNamedDeclaration {
+ return node.type === AST_NODE_TYPES.ExportNamedDeclaration;
+}
+
+export function isExpressionStatement(
+ node: TSESTree.Node,
+): node is TSESTree.ExpressionStatement {
+ return node && node.type === AST_NODE_TYPES.ExpressionStatement;
+}
+
+export function isFunctionDeclaration(
+ node: TSESTree.Node,
+): node is TSESTree.FunctionDeclaration {
+ return node.type === AST_NODE_TYPES.FunctionDeclaration;
+}
+
+export function isFunctionExpression(
+ node: TSESTree.Node,
+): node is TSESTree.FunctionExpression {
+ return node.type === AST_NODE_TYPES.FunctionExpression;
+}
+
+export function isIdentifier(node: TSESTree.Node): node is TSESTree.Identifier {
+ return node.type === AST_NODE_TYPES.Identifier;
+}
+
+export function isImportDeclaration(node: TSESTree.Node): node is TSESTree.ImportDeclaration {
+ return node.type === AST_NODE_TYPES.ImportDeclaration;
+}
+
+export function isImportNamespaceSpecifier(node: TSESTree.Node): node is TSESTree.ImportNamespaceSpecifier {
+ return node.type === AST_NODE_TYPES.ImportNamespaceSpecifier;
+}
+
+export function isImportSpecifier(node: TSESTree.Node): node is TSESTree.ImportSpecifier {
+ return node.type === AST_NODE_TYPES.ImportSpecifier;
+}
+
+export function isJSXExpressionContainer(node: TSESTree.Node): node is TSESTree.JSXExpressionContainer {
+ return node.type === AST_NODE_TYPES.JSXExpressionContainer;
+}
+
+export function isLiteral(node: TSESTree.Node): node is TSESTree.Literal {
+ return node.type === AST_NODE_TYPES.Literal;
+}
+
+export function isMemberExpression(node: TSESTree.Node): node is TSESTree.MemberExpression {
+ return node.type === AST_NODE_TYPES.MemberExpression;
+}
+
+export function isMethodDefinition(node: TSESTree.Node): node is TSESTree.MethodDefinition {
+ return node.type === AST_NODE_TYPES.MethodDefinition;
+}
+
+export function isNewExpression(node: TSESTree.Node): node is TSESTree.NewExpression {
+ return node.type === AST_NODE_TYPES.NewExpression;
+}
+
+export function isObjectExpression(node: TSESTree.Node): node is TSESTree.ObjectExpression {
+ return node.type === AST_NODE_TYPES.ObjectExpression;
+}
+
+export function isObjectPattern(node: TSESTree.Node): node is TSESTree.ObjectPattern {
+ return node.type === AST_NODE_TYPES.ObjectPattern;
+}
+
+export function isProgram(node: TSESTree.Node): node is TSESTree.Program {
+ return node.type === AST_NODE_TYPES.Program;
+}
+
+export function isProperty(node: TSESTree.Node): node is TSESTree.Property {
+ return node.type === AST_NODE_TYPES.Property;
+}
+
+export function isPropertyDefinition(node: TSESTree.Node): node is TSESTree.PropertyDefinition {
+ return node.type === AST_NODE_TYPES.PropertyDefinition;
+}
+
+export function isPrivateIdentifier(
+ node: TSESTree.Node,
+): node is TSESTree.PrivateIdentifier {
+ return node.type === AST_NODE_TYPES.PrivateIdentifier;
+}
+
+export function isRestElement(node: TSESTree.Node): node is TSESTree.RestElement {
+ return node.type === AST_NODE_TYPES.RestElement;
+}
+
+export function isThisExpression(node: TSESTree.Node): node is TSESTree.ThisExpression {
+ return node.type === AST_NODE_TYPES.ThisExpression;
+}
+
+export function isTSTypeLiteral(node: TSESTree.Node): node is TSESTree.TSTypeLiteral {
+ return node.type === AST_NODE_TYPES.TSTypeLiteral;
+}
+
+export function isTSTypeReference(node: TSESTree.Node): node is TSESTree.TSTypeReference {
+ return node.type === AST_NODE_TYPES.TSTypeReference;
+}
+
+export function isUnaryExpression(node: TSESTree.Node): node is TSESTree.UnaryExpression {
+ return node.type === AST_NODE_TYPES.UnaryExpression;
+}
+
+export function isVariableDeclarator(
+ node: TSESTree.Node,
+): node is TSESTree.VariableDeclarator {
+ return node.type === AST_NODE_TYPES.VariableDeclarator;
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 00000000..cf693fa2
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,111 @@
+import { TSESLint } from '@typescript-eslint/utils';
+import { name, version } from '../package.json';
+import { createRecommendedConfig } from './configs/recommended';
+import { createStrictConfig } from './configs/strict';
+
+import { banObservablesRule } from './rules/ban-observables';
+import { banOperatorsRule } from './rules/ban-operators';
+import { finnishRule } from './rules/finnish';
+import { justRule } from './rules/just';
+import { macroRule } from './rules/macro';
+import { noAsyncSubscribeRule } from './rules/no-async-subscribe';
+import { noCompatRule } from './rules/no-compat';
+import { noConnectableRule } from './rules/no-connectable';
+import { noCreateRule } from './rules/no-create';
+import { noCyclicActionRule } from './rules/no-cyclic-action';
+import { noExplicitGenericsRule } from './rules/no-explicit-generics';
+import { noExposedSubjectsRule } from './rules/no-exposed-subjects';
+import { noFinnishRule } from './rules/no-finnish';
+import { noFloatingObservablesRule } from './rules/no-floating-observables';
+import { noIgnoredDefaultValueRule } from './rules/no-ignored-default-value';
+import { noIgnoredErrorRule } from './rules/no-ignored-error';
+import { noIgnoredNotifierRule } from './rules/no-ignored-notifier';
+import { noIgnoredReplayBufferRule } from './rules/no-ignored-replay-buffer';
+import { noIgnoredSubscribeRule } from './rules/no-ignored-subscribe';
+import { noIgnoredSubscriptionRule } from './rules/no-ignored-subscription';
+import { noIgnoredTakewhileValueRule } from './rules/no-ignored-takewhile-value';
+import { noImplicitAnyCatchRule } from './rules/no-implicit-any-catch';
+import { noIndexRule } from './rules/no-index';
+import { noInternalRule } from './rules/no-internal';
+import { noMisusedObservablesRule } from './rules/no-misused-observables';
+import { noNestedSubscribeRule } from './rules/no-nested-subscribe';
+import { noRedundantNotifyRule } from './rules/no-redundant-notify';
+import { noSharereplayRule } from './rules/no-sharereplay';
+import { noSubclassRule } from './rules/no-subclass';
+import { noSubjectUnsubscribeRule } from './rules/no-subject-unsubscribe';
+import { noSubjectValueRule } from './rules/no-subject-value';
+import { noSubscribeHandlersRule } from './rules/no-subscribe-handlers';
+import { noSubscribeInPipeRule } from './rules/no-subscribe-in-pipe';
+import { noTapRule } from './rules/no-tap';
+import { noTopromiseRule } from './rules/no-topromise';
+import { noUnboundMethodsRule } from './rules/no-unbound-methods';
+import { noUnsafeCatchRule } from './rules/no-unsafe-catch';
+import { noUnsafeFirstRule } from './rules/no-unsafe-first';
+import { noUnsafeSubjectNext } from './rules/no-unsafe-subject-next';
+import { noUnsafeSwitchmapRule } from './rules/no-unsafe-switchmap';
+import { noUnsafeTakeuntilRule } from './rules/no-unsafe-takeuntil';
+import { preferObserverRule } from './rules/prefer-observer';
+import { preferRootOperatorsRule } from './rules/prefer-root-operators';
+import { suffixSubjectsRule } from './rules/suffix-subjects';
+import { throwErrorRule } from './rules/throw-error';
+
+const plugin = {
+ meta: { name, version },
+ rules: {
+ 'ban-observables': banObservablesRule,
+ 'ban-operators': banOperatorsRule,
+ 'finnish': finnishRule,
+ 'just': justRule,
+ 'macro': macroRule,
+ 'no-async-subscribe': noAsyncSubscribeRule,
+ 'no-compat': noCompatRule,
+ 'no-connectable': noConnectableRule,
+ 'no-create': noCreateRule,
+ 'no-cyclic-action': noCyclicActionRule,
+ 'no-explicit-generics': noExplicitGenericsRule,
+ 'no-exposed-subjects': noExposedSubjectsRule,
+ 'no-finnish': noFinnishRule,
+ 'no-floating-observables': noFloatingObservablesRule,
+ 'no-ignored-default-value': noIgnoredDefaultValueRule,
+ 'no-ignored-error': noIgnoredErrorRule,
+ 'no-ignored-notifier': noIgnoredNotifierRule,
+ 'no-ignored-replay-buffer': noIgnoredReplayBufferRule,
+ 'no-ignored-subscribe': noIgnoredSubscribeRule,
+ 'no-ignored-subscription': noIgnoredSubscriptionRule,
+ 'no-ignored-takewhile-value': noIgnoredTakewhileValueRule,
+ 'no-implicit-any-catch': noImplicitAnyCatchRule,
+ 'no-index': noIndexRule,
+ 'no-internal': noInternalRule,
+ 'no-misused-observables': noMisusedObservablesRule,
+ 'no-nested-subscribe': noNestedSubscribeRule,
+ 'no-redundant-notify': noRedundantNotifyRule,
+ 'no-sharereplay': noSharereplayRule,
+ 'no-subclass': noSubclassRule,
+ 'no-subject-unsubscribe': noSubjectUnsubscribeRule,
+ 'no-subject-value': noSubjectValueRule,
+ 'no-subscribe-handlers': noSubscribeHandlersRule,
+ 'no-subscribe-in-pipe': noSubscribeInPipeRule,
+ 'no-tap': noTapRule,
+ 'no-topromise': noTopromiseRule,
+ 'no-unbound-methods': noUnboundMethodsRule,
+ 'no-unsafe-catch': noUnsafeCatchRule,
+ 'no-unsafe-first': noUnsafeFirstRule,
+ 'no-unsafe-subject-next': noUnsafeSubjectNext,
+ 'no-unsafe-switchmap': noUnsafeSwitchmapRule,
+ 'no-unsafe-takeuntil': noUnsafeTakeuntilRule,
+ 'prefer-observer': preferObserverRule,
+ 'prefer-root-operators': preferRootOperatorsRule,
+ 'suffix-subjects': suffixSubjectsRule,
+ 'throw-error': throwErrorRule,
+ },
+} satisfies TSESLint.FlatConfig.Plugin;
+
+const rxjsX = {
+ ...plugin,
+ configs: {
+ recommended: createRecommendedConfig(plugin),
+ strict: createStrictConfig(plugin),
+ },
+} satisfies TSESLint.FlatConfig.Plugin;
+
+export default rxjsX;
diff --git a/source/rules/ban-observables.ts b/src/rules/ban-observables.ts
similarity index 54%
rename from source/rules/ban-observables.ts
rename to src/rules/ban-observables.ts
index 07d5ea47..32401e9f 100644
--- a/source/rules/ban-observables.ts
+++ b/src/rules/ban-observables.ts
@@ -1,39 +1,31 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import { ruleCreator } from "../utils";
+import { AST_NODE_TYPES, TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly Record[] = [];
-const rule = ruleCreator({
+export const banObservablesRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids the use of banned observables.",
- recommended: false,
+ description: 'Disallow banned observable creators.',
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "RxJS observable is banned: {{name}}{{explanation}}.",
+ forbidden: 'RxJS observable is banned: {{name}}{{explanation}}.',
},
schema: [
{
- type: "object",
+ type: 'object',
description: stripIndent`
An object containing keys that are names of observable factory functions
and values that are either booleans or strings containing the explanation for the ban.`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "ban-observables",
- create: (context, unused: typeof defaultOptions) => {
- let bans: { explanation: string; regExp: RegExp }[] = [];
+ name: 'ban-observables',
+ create: (context) => {
+ const bans: { explanation: string; regExp: RegExp }[] = [];
const [config] = context.options;
if (!config) {
@@ -43,7 +35,7 @@ const rule = ruleCreator({
Object.entries(config).forEach(([key, value]) => {
if (value !== false) {
bans.push({
- explanation: typeof value === "string" ? value : "",
+ explanation: typeof value === 'string' ? value : '',
regExp: new RegExp(`^${key}$`),
});
}
@@ -53,9 +45,9 @@ const rule = ruleCreator({
for (let b = 0, length = bans.length; b < length; ++b) {
const ban = bans[b];
if (ban.regExp.test(name)) {
- const explanation = ban.explanation ? `: ${ban.explanation}` : "";
+ const explanation = ban.explanation ? `: ${ban.explanation}` : '';
return {
- messageId: "forbidden",
+ messageId: 'forbidden',
data: { name, explanation },
} as const;
}
@@ -64,11 +56,12 @@ const rule = ruleCreator({
}
return {
- "ImportDeclaration[source.value='rxjs'] > ImportSpecifier": (
- node: es.ImportSpecifier
+ 'ImportDeclaration[source.value=\'rxjs\'] > ImportSpecifier': (
+ node: es.ImportSpecifier,
) => {
const identifier = node.imported;
- const failure = getFailure(identifier.name);
+ const name = identifier.type === AST_NODE_TYPES.Identifier ? identifier.name : identifier.value;
+ const failure = getFailure(name);
if (failure) {
context.report({
...failure,
@@ -79,5 +72,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/ban-operators.ts b/src/rules/ban-operators.ts
new file mode 100644
index 00000000..2c232a16
--- /dev/null
+++ b/src/rules/ban-operators.ts
@@ -0,0 +1,71 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+const defaultOptions: readonly Record[] = [];
+
+export const banOperatorsRule = ruleCreator({
+ defaultOptions,
+ meta: {
+ docs: {
+ description: 'Disallow banned operators.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'RxJS operator is banned: {{name}}{{explanation}}.',
+ },
+ schema: [
+ {
+ type: 'object',
+ description: stripIndent`
+ An object containing keys that are names of operators
+ and values that are either booleans or strings containing the explanation for the ban.`,
+ },
+ ],
+ type: 'problem',
+ },
+ name: 'ban-operators',
+ create: (context) => {
+ const { couldBeType } = getTypeServices(context);
+ const bans: { name: string; explanation: string }[] = [];
+
+ const [config] = context.options;
+ if (!config) {
+ return {};
+ }
+
+ Object.entries(config).forEach(([key, value]) => {
+ if (value !== false) {
+ bans.push({
+ name: key,
+ explanation: typeof value === 'string' ? value : '',
+ });
+ }
+ });
+
+ function checkNode(node: es.Node) {
+ for (const ban of bans) {
+ if (couldBeType(node, ban.name, { name: /[/\\]rxjs[/\\]/ })) {
+ const explanation = ban.explanation ? `: ${ban.explanation}` : '';
+ context.report({
+ messageId: 'forbidden',
+ data: { name: ban.name, explanation },
+ node,
+ });
+ return;
+ }
+ }
+ }
+
+ return {
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.name]': (node: es.CallExpression) => {
+ checkNode(node.callee);
+ },
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.type="MemberExpression"]': (node: es.CallExpression) => {
+ const callee = node.callee as es.MemberExpression;
+ checkNode(callee.property);
+ },
+ };
+ },
+});
diff --git a/source/rules/finnish.ts b/src/rules/finnish.ts
similarity index 55%
rename from source/rules/finnish.ts
rename to src/rules/finnish.ts
index 70291c7f..78f869ac 100644
--- a/source/rules/finnish.ts
+++ b/src/rules/finnish.ts
@@ -1,17 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
+import { AST_NODE_TYPES, TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
import {
findParent,
getLoc,
- getParent,
- getParserServices,
- getTypeServices,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+ getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly {
functions?: boolean;
@@ -24,39 +16,37 @@ const defaultOptions: readonly {
variables?: boolean;
}[] = [];
-const rule = ruleCreator({
+export const finnishRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Enforces the use of Finnish notation.",
- recommended: false,
+ description: 'Enforce Finnish notation.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- shouldBeFinnish: "Finnish notation should be used here.",
- shouldNotBeFinnish: "Finnish notation should not be used here.",
+ shouldBeFinnish: 'Finnish notation should be used here.',
+ shouldNotBeFinnish: 'Finnish notation should not be used here.',
},
schema: [
{
properties: {
- functions: { type: "boolean" },
- methods: { type: "boolean" },
- names: { type: "object" },
- parameters: { type: "boolean" },
- properties: { type: "boolean" },
- strict: { type: "boolean" },
- types: { type: "object" },
- variables: { type: "boolean" },
+ functions: { type: 'boolean', description: 'Require for functions.' },
+ methods: { type: 'boolean', description: 'Require for methods.' },
+ names: { type: 'object', description: 'Enforce for specific names. Keys are a RegExp, values are a boolean.' },
+ parameters: { type: 'boolean', description: 'Require for parameters.' },
+ properties: { type: 'boolean', description: 'Require for properties.' },
+ strict: { type: 'boolean', description: 'Disallow Finnish notation for non-Observables.' },
+ types: { type: 'object', description: 'Enforce for specific types. Keys are a RegExp, values are a boolean.' },
+ variables: { type: 'boolean', description: 'Require for variables.' },
},
- type: "object",
+ type: 'object',
},
],
- type: "problem",
+ type: 'problem',
},
- name: "finnish",
- create: (context, unused: typeof defaultOptions) => {
- const { esTreeNodeToTSNodeMap } = getParserServices(context);
+ name: 'finnish',
+ create: (context) => {
+ const { esTreeNodeToTSNodeMap } = ESLintUtils.getParserServices(context);
const {
couldBeObservable,
couldBeType,
@@ -80,7 +70,7 @@ const rule = ruleCreator({
Object.entries(config.names).forEach(
([key, validate]: [string, boolean]) => {
names.push({ regExp: new RegExp(key), validate });
- }
+ },
);
} else {
names.push({
@@ -95,7 +85,7 @@ const rule = ruleCreator({
Object.entries(config.types).forEach(
([key, validate]: [string, boolean]) => {
types.push({ regExp: new RegExp(key), validate });
- }
+ },
);
} else {
types.push({
@@ -105,29 +95,31 @@ const rule = ruleCreator({
}
function checkNode(nameNode: es.Node, typeNode?: es.Node) {
- let tsNode = esTreeNodeToTSNodeMap.get(nameNode);
+ const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
const text = tsNode.getText();
- const hasFinnish = /\$$/.test(text);
+ const hasFinnish = text.endsWith('$');
if (hasFinnish && !strict) {
return;
}
const shouldBeFinnish = hasFinnish
- ? () => {}
- : () =>
+ ? () => { /* noop */ }
+ : () => {
context.report({
loc: getLoc(tsNode),
- messageId: "shouldBeFinnish",
+ messageId: 'shouldBeFinnish',
});
+ };
const shouldNotBeFinnish = hasFinnish
- ? () =>
+ ? () => {
context.report({
loc: getLoc(tsNode),
- messageId: "shouldNotBeFinnish",
- })
- : () => {};
+ messageId: 'shouldNotBeFinnish',
+ });
+ }
+ : () => { /* noop */ };
if (
- couldBeObservable(typeNode || nameNode) ||
- couldReturnObservable(typeNode || nameNode)
+ couldBeObservable(typeNode ?? nameNode)
+ || couldReturnObservable(typeNode ?? nameNode)
) {
for (const name of names) {
const { regExp, validate } = name;
@@ -139,9 +131,9 @@ const rule = ruleCreator({
for (const type of types) {
const { regExp, validate } = type;
if (
- (couldBeType(typeNode || nameNode, regExp) ||
- couldReturnType(typeNode || nameNode, regExp)) &&
- !validate
+ (couldBeType(typeNode ?? nameNode, regExp)
+ || couldReturnType(typeNode ?? nameNode, regExp))
+ && !validate
) {
shouldNotBeFinnish();
return;
@@ -154,18 +146,18 @@ const rule = ruleCreator({
}
return {
- "ArrayPattern > Identifier": (node: es.Identifier) => {
+ 'ArrayPattern > Identifier': (node: es.Identifier) => {
const found = findParent(
node,
- "ArrowFunctionExpression",
- "FunctionDeclaration",
- "FunctionExpression",
- "VariableDeclarator"
+ 'ArrowFunctionExpression',
+ 'FunctionDeclaration',
+ 'FunctionExpression',
+ 'VariableDeclarator',
);
if (!found) {
return;
}
- if (!validate.variables && found.type === "VariableDeclarator") {
+ if (!validate.variables && found.type === AST_NODE_TYPES.VariableDeclarator) {
return;
}
if (!validate.parameters) {
@@ -173,21 +165,21 @@ const rule = ruleCreator({
}
checkNode(node);
},
- "ArrowFunctionExpression > Identifier": (node: es.Identifier) => {
+ 'ArrowFunctionExpression > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
- const parent = getParent(node) as es.ArrowFunctionExpression;
+ const parent = node.parent as es.ArrowFunctionExpression;
if (node !== parent.body) {
checkNode(node);
}
}
},
- "PropertyDefinition[computed=false]": (node: es.PropertyDefinition) => {
+ 'PropertyDefinition[computed=false]': (node: es.PropertyDefinition) => {
if (validate.properties) {
checkNode(node.key);
}
},
- "FunctionDeclaration > Identifier": (node: es.Identifier) => {
- const parent = getParent(node) as es.FunctionDeclaration;
+ 'FunctionDeclaration > Identifier': (node: es.Identifier) => {
+ const parent = node.parent as es.FunctionDeclaration;
if (node === parent.id) {
if (validate.functions) {
checkNode(node, parent);
@@ -198,8 +190,8 @@ const rule = ruleCreator({
}
}
},
- "FunctionExpression > Identifier": (node: es.Identifier) => {
- const parent = getParent(node) as es.FunctionExpression;
+ 'FunctionExpression > Identifier': (node: es.Identifier) => {
+ const parent = node.parent as es.FunctionExpression;
if (node === parent.id) {
if (validate.functions) {
checkNode(node, parent);
@@ -210,89 +202,91 @@ const rule = ruleCreator({
}
}
},
- "MethodDefinition[kind='get'][computed=false]": (
- node: es.MethodDefinition
+ 'MethodDefinition[kind=\'get\'][computed=false]': (
+ node: es.MethodDefinition,
) => {
if (validate.properties) {
checkNode(node.key, node);
}
},
- "MethodDefinition[kind='method'][computed=false]": (
- node: es.MethodDefinition
+ 'MethodDefinition[kind=\'method\'][computed=false]': (
+ node: es.MethodDefinition,
) => {
if (validate.methods) {
checkNode(node.key, node);
}
},
- "MethodDefinition[kind='set'][computed=false]": (
- node: es.MethodDefinition
+ 'MethodDefinition[kind=\'set\'][computed=false]': (
+ node: es.MethodDefinition,
) => {
if (validate.properties) {
checkNode(node.key, node);
}
},
- "ObjectExpression > Property[computed=false] > Identifier": (
- node: es.Identifier
+ 'ObjectExpression > Property[computed=false] > Identifier': (
+ node: es.Identifier,
) => {
if (validate.properties) {
- const parent = getParent(node) as es.Property;
+ const parent = node.parent as es.Property;
if (node === parent.key) {
checkNode(node);
}
}
},
- "ObjectPattern > Property > Identifier": (node: es.Identifier) => {
+ 'ObjectPattern > Property > Identifier': (node: es.Identifier) => {
const found = findParent(
node,
- "ArrowFunctionExpression",
- "FunctionDeclaration",
- "FunctionExpression",
- "VariableDeclarator"
+ 'ArrowFunctionExpression',
+ 'FunctionDeclaration',
+ 'FunctionExpression',
+ 'VariableDeclarator',
);
if (!found) {
return;
}
- if (!validate.variables && found.type === "VariableDeclarator") {
+ if (!validate.variables && found.type === AST_NODE_TYPES.VariableDeclarator) {
return;
}
if (!validate.parameters) {
return;
}
- const parent = getParent(node) as es.Property;
+ const parent = node.parent as es.Property;
if (node === parent.value) {
checkNode(node);
}
},
- "TSCallSignatureDeclaration > Identifier": (node: es.Identifier) => {
+ 'TSCallSignatureDeclaration > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
checkNode(node);
}
},
- "TSConstructSignatureDeclaration > Identifier": (node: es.Identifier) => {
+ 'TSConstructSignatureDeclaration > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
checkNode(node);
}
},
- "TSMethodSignature[computed=false]": (node: es.TSMethodSignature) => {
+ 'TSMethodSignature[computed=false]': (node: es.TSMethodSignature) => {
if (validate.methods) {
checkNode(node.key, node);
}
if (validate.parameters) {
- node.params.forEach((param: es.Node) => checkNode(param));
+ node.params.forEach((param: es.Node) => {
+ checkNode(param);
+ });
}
},
- "TSParameterProperty > Identifier": (node: es.Identifier) => {
+ 'TSParameterProperty > Identifier': (node: es.Identifier) => {
if (validate.parameters || validate.properties) {
checkNode(node);
}
},
- "TSPropertySignature[computed=false]": (node: es.TSPropertySignature) => {
+ 'TSPropertySignature[computed=false]': (node: es.TSPropertySignature) => {
if (validate.properties) {
checkNode(node.key);
}
},
- "VariableDeclarator > Identifier": (node: es.Identifier) => {
- const parent = getParent(node) as es.VariableDeclarator;
+ 'VariableDeclarator > Identifier': (node: es.Identifier) => {
+ const parent = node.parent as es.VariableDeclarator;
if (validate.variables && node === parent.id) {
checkNode(node);
}
@@ -300,5 +294,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/just.ts b/src/rules/just.ts
new file mode 100644
index 00000000..ab15a9a1
--- /dev/null
+++ b/src/rules/just.ts
@@ -0,0 +1,48 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
+
+export const justRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Require the use of `just` instead of `of`.',
+ },
+ fixable: 'code',
+ messages: {
+ forbidden: 'Use just alias.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'just',
+ create: (context) => {
+ return {
+ 'ImportDeclaration[source.value=\'rxjs\'] > ImportSpecifier[imported.name=\'of\']':
+ (node: es.ImportSpecifier) => {
+ // import declaration has been renamed
+ if (
+ node.local.range[0] !== node.imported.range[0]
+ && node.local.range[1] !== node.imported.range[1]
+ ) {
+ return;
+ }
+
+ context.report({
+ messageId: 'forbidden',
+ node,
+ fix: (fixer) => fixer.replaceTextRange(node.range, 'of as just'),
+ });
+
+ const [ofImport] = context.sourceCode.getDeclaredVariables(node);
+ ofImport.references.forEach((ref) => {
+ context.report({
+ messageId: 'forbidden',
+ node: ref.identifier,
+ fix: (fixer) =>
+ fixer.replaceTextRange(ref.identifier.range, 'just'),
+ });
+ });
+ },
+ };
+ },
+});
diff --git a/source/rules/macro.ts b/src/rules/macro.ts
similarity index 53%
rename from source/rules/macro.ts
rename to src/rules/macro.ts
index 4d0d9c29..ab0ead34 100644
--- a/source/rules/macro.ts
+++ b/src/rules/macro.ts
@@ -1,30 +1,24 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
import {
- TSESLint as eslint,
TSESTree as es,
-} from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
+ TSESLint as eslint,
+} from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
-const rule = ruleCreator({
+export const macroRule = ruleCreator({
defaultOptions: [],
meta: {
+ deprecated: true,
docs: {
- description: "Enforces the use of the RxJS Tools Babel macro.",
- recommended: false,
+ description: 'Require the use of the RxJS Tools Babel macro.',
},
- fixable: "code",
- hasSuggestions: false,
+ fixable: 'code',
messages: {
- macro: "Use the RxJS Tools Babel macro.",
+ macro: 'Use the RxJS Tools Babel macro.',
},
schema: [],
- type: "problem",
+ type: 'problem',
},
- name: "macro",
+ name: 'macro',
create: (context) => {
let hasFailure = false;
let hasMacroImport = false;
@@ -34,13 +28,13 @@ const rule = ruleCreator({
return fixer.insertTextBefore(
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
program!,
- `import "babel-plugin-rxjs-tools/macro";\n`
+ `import "babel-plugin-rxjs-tools/macro";\n`,
);
}
return {
- "CallExpression[callee.property.name=/^(pipe|subscribe)$/]": (
- node: es.CallExpression
+ 'CallExpression[callee.property.name=/^(pipe|subscribe)$/]': (
+ node: es.CallExpression,
) => {
if (hasFailure || hasMacroImport) {
return;
@@ -48,17 +42,17 @@ const rule = ruleCreator({
hasFailure = true;
context.report({
fix,
- messageId: "macro",
+ messageId: 'macro',
node: node.callee,
});
},
- "ImportDeclaration[source.value='babel-plugin-rxjs-tools/macro']": (
- node: es.ImportDeclaration
+ 'ImportDeclaration[source.value=\'babel-plugin-rxjs-tools/macro\']': (
+ _node: es.ImportDeclaration,
) => {
hasMacroImport = true;
},
[String.raw`ImportDeclaration[source.value=/^rxjs(\u002f|$)/]`]: (
- node: es.ImportDeclaration
+ node: es.ImportDeclaration,
) => {
if (hasFailure || hasMacroImport) {
return;
@@ -66,15 +60,13 @@ const rule = ruleCreator({
hasFailure = true;
context.report({
fix,
- messageId: "macro",
+ messageId: 'macro',
node,
});
},
- Program: (node: es.Program) => {
+ 'Program': (node: es.Program) => {
program = node;
},
};
},
});
-
-export = rule;
diff --git a/src/rules/no-async-subscribe.ts b/src/rules/no-async-subscribe.ts
new file mode 100644
index 00000000..89127af3
--- /dev/null
+++ b/src/rules/no-async-subscribe.ts
@@ -0,0 +1,53 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noAsyncSubscribeRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow passing `async` functions to `subscribe`.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Passing async functions to subscribe is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-async-subscribe',
+ create: (context) => {
+ const { couldBeObservable } = getTypeServices(context);
+
+ function checkNode(
+ node: es.FunctionExpression | es.ArrowFunctionExpression,
+ ) {
+ const parentNode = node.parent as es.CallExpression;
+ const callee = parentNode.callee as es.MemberExpression;
+
+ if (couldBeObservable(callee.object)) {
+ const { loc } = node;
+ // only report the `async` keyword
+ const asyncLoc = {
+ ...loc,
+ end: {
+ ...loc.start,
+ column: loc.start.column + 5,
+ },
+ };
+
+ context.report({
+ messageId: 'forbidden',
+ loc: asyncLoc,
+ });
+ }
+ }
+ return {
+ 'CallExpression[callee.property.name=\'subscribe\'] > FunctionExpression[async=true]':
+ checkNode,
+ 'CallExpression[callee.property.name=\'subscribe\'] > ArrowFunctionExpression[async=true]':
+ checkNode,
+ };
+ },
+});
diff --git a/src/rules/no-compat.ts b/src/rules/no-compat.ts
new file mode 100644
index 00000000..84046427
--- /dev/null
+++ b/src/rules/no-compat.ts
@@ -0,0 +1,30 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
+
+export const noCompatRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ deprecated: true,
+ docs: {
+ description:
+ 'Disallow the `rxjs-compat` package.',
+ },
+ messages: {
+ forbidden: '\'rxjs-compat\'-dependent import locations are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-compat',
+ create: (context) => {
+ return {
+ [String.raw`ImportDeclaration Literal[value=/^rxjs\u002f/]:not(Literal[value=/^rxjs\u002f(ajax|fetch|operators|testing|webSocket)/])`]:
+ (node: es.Literal) => {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ },
+ };
+ },
+});
diff --git a/src/rules/no-connectable.ts b/src/rules/no-connectable.ts
new file mode 100644
index 00000000..cf8d51dc
--- /dev/null
+++ b/src/rules/no-connectable.ts
@@ -0,0 +1,41 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noConnectableRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow operators that return connectable observables.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Connectable observables are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-connectable',
+ create: (context) => {
+ const { couldBeFunction } = getTypeServices(context);
+ return {
+ 'CallExpression[callee.name=\'multicast\']': (node: es.CallExpression) => {
+ if (node.arguments.length === 1) {
+ context.report({
+ messageId: 'forbidden',
+ node: node.callee,
+ });
+ }
+ },
+ 'CallExpression[callee.name=/^(publish|publishBehavior|publishLast|publishReplay)$/]':
+ (node: es.CallExpression) => {
+ if (!node.arguments.some((arg) => couldBeFunction(arg))) {
+ context.report({
+ messageId: 'forbidden',
+ node: node.callee,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-create.ts b/src/rules/no-create.ts
new file mode 100644
index 00000000..c7a17f24
--- /dev/null
+++ b/src/rules/no-create.ts
@@ -0,0 +1,36 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noCreateRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow the static `Observable.create` function.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Observable.create is forbidden; use new Observable.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-create',
+ create: (context) => {
+ const { couldBeObservable } = getTypeServices(context);
+
+ return {
+ 'CallExpression > MemberExpression[object.name=\'Observable\'] > Identifier[name=\'create\']':
+ (node: es.Identifier) => {
+ const memberExpression = node.parent as es.MemberExpression;
+ if (couldBeObservable(memberExpression.object)) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/source/rules/no-cyclic-action.ts b/src/rules/no-cyclic-action.ts
similarity index 60%
rename from source/rules/no-cyclic-action.ts
rename to src/rules/no-cyclic-action.ts
index 0a9e2550..6e85e3e5 100644
--- a/source/rules/no-cyclic-action.ts
+++ b/src/rules/no-cyclic-action.ts
@@ -1,16 +1,12 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import { getTypeServices, isCallExpression, isIdentifier } from "eslint-etc";
-import ts from "typescript";
-import { defaultObservable } from "../constants";
-import { ruleCreator } from "../utils";
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import ts from 'typescript';
+import { defaultObservable } from '../constants';
+import { isCallExpression, isIdentifier } from '../etc';
+import { ruleCreator } from '../utils';
function isTypeReference(type: ts.Type): type is ts.TypeReference {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
return Boolean((type as any).target);
}
@@ -18,70 +14,69 @@ const defaultOptions: readonly {
observable?: string;
}[] = [];
-const rule = ruleCreator({
- defaultOptions: [],
+export const noCyclicActionRule = ruleCreator({
+ defaultOptions,
meta: {
docs: {
- description: "Forbids effects and epics that re-emit filtered actions.",
- recommended: false,
+ description: 'Disallow cyclic actions in effects and epics.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
forbidden:
- "Effects and epics that re-emit filtered actions are forbidden.",
+ 'Effects and epics that re-emit filtered actions are forbidden.',
},
schema: [
{
properties: {
- observable: { type: "string" },
+ observable: { type: 'string', description: 'A RegExp that matches an effect or epic\'s actions observable.', default: defaultObservable },
},
- type: "object",
+ type: 'object',
description: stripIndent`
An optional object with an optional \`observable\` property.
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-cyclic-action",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-cyclic-action',
+ create: (context) => {
const [config = {}] = context.options;
const { observable = defaultObservable } = config;
const observableRegExp = new RegExp(observable);
- const { getType, typeChecker } = getTypeServices(context);
+ const { getTypeAtLocation, program } = ESLintUtils.getParserServices(context);
+ const typeChecker = program.getTypeChecker();
function checkNode(pipeCallExpression: es.CallExpression) {
const operatorCallExpression = pipeCallExpression.arguments.find(
(arg) =>
- isCallExpression(arg) &&
- isIdentifier(arg.callee) &&
- arg.callee.name === "ofType"
+ isCallExpression(arg)
+ && isIdentifier(arg.callee)
+ && arg.callee.name === 'ofType',
);
if (!operatorCallExpression) {
return;
}
- const operatorType = getType(operatorCallExpression);
+ const operatorType = getTypeAtLocation(operatorCallExpression);
const [signature] = typeChecker.getSignaturesOfType(
operatorType,
- ts.SignatureKind.Call
+ ts.SignatureKind.Call,
);
if (!signature) {
return;
}
- const operatorReturnType =
- typeChecker.getReturnTypeOfSignature(signature);
+ const operatorReturnType
+ = typeChecker.getReturnTypeOfSignature(signature);
if (!isTypeReference(operatorReturnType)) {
return;
}
- const [operatorElementType] =
- typeChecker.getTypeArguments(operatorReturnType);
+ const [operatorElementType]
+ = typeChecker.getTypeArguments(operatorReturnType);
if (!operatorElementType) {
return;
}
- const pipeType = getType(pipeCallExpression);
+ const pipeType = getTypeAtLocation(pipeCallExpression);
if (!isTypeReference(pipeType)) {
return;
}
@@ -95,7 +90,7 @@ const rule = ruleCreator({
for (const actionType of operatorActionTypes) {
if (pipeActionTypes.includes(actionType)) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: pipeCallExpression.callee,
});
return;
@@ -111,13 +106,13 @@ const rule = ruleCreator({
}
return memberActionTypes;
}
- const symbol = typeChecker.getPropertyOfType(type, "type");
- if (!symbol || !symbol.valueDeclaration) {
+ const symbol = typeChecker.getPropertyOfType(type, 'type');
+ if (!symbol?.valueDeclaration) {
return [];
}
const actionType = typeChecker.getTypeOfSymbolAtLocation(
symbol,
- symbol.valueDeclaration
+ symbol.valueDeclaration,
);
return [typeChecker.typeToString(actionType)];
}
@@ -130,5 +125,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-explicit-generics.ts b/src/rules/no-explicit-generics.ts
new file mode 100644
index 00000000..c2612891
--- /dev/null
+++ b/src/rules/no-explicit-generics.ts
@@ -0,0 +1,60 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { isArrayExpression, isObjectExpression } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noExplicitGenericsRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow unnecessary explicit generic type arguments.',
+ recommended: 'strict',
+ },
+ messages: {
+ forbidden: 'Explicit generic type arguments are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-explicit-generics',
+ create: (context) => {
+ function report(node: es.Node) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+
+ function checkBehaviorSubjects(node: es.Node) {
+ const parent = node.parent as es.NewExpression;
+ const {
+ arguments: [value],
+ } = parent;
+ if (isArrayExpression(value) || isObjectExpression(value)) {
+ return;
+ }
+ report(node);
+ }
+
+ function checkNotifications(node: es.Node) {
+ const parent = node.parent as es.NewExpression;
+ const {
+ arguments: [, value],
+ } = parent;
+ if (isArrayExpression(value) || isObjectExpression(value)) {
+ return;
+ }
+ report(node);
+ }
+
+ return {
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[typeArguments.params.length > 0] > Identifier':
+ report,
+ 'NewExpression[typeArguments.params.length > 0] > Identifier[name=\'BehaviorSubject\']':
+ checkBehaviorSubjects,
+ 'CallExpression[typeArguments.params.length > 0] > Identifier[name=/^(from|of)$/]':
+ report,
+ 'NewExpression[typeArguments.params.length > 0][arguments.0.value=\'N\'] > Identifier[name=\'Notification\']':
+ checkNotifications,
+ };
+ },
+});
diff --git a/source/rules/no-exposed-subjects.ts b/src/rules/no-exposed-subjects.ts
similarity index 73%
rename from source/rules/no-exposed-subjects.ts
rename to src/rules/no-exposed-subjects.ts
index 085ba56d..f32e6473 100644
--- a/source/rules/no-exposed-subjects.ts
+++ b/src/rules/no-exposed-subjects.ts
@@ -1,48 +1,42 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { getTypeServices, isIdentifier } from "eslint-etc";
-import { ruleCreator } from "../utils";
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices, isIdentifier } from '../etc';
+import { ruleCreator } from '../utils';
const defaultAllowedTypesRegExp = /^EventEmitter$/;
const defaultOptions: readonly {
allowProtected?: boolean;
}[] = [];
-const rule = ruleCreator({
+export const noExposedSubjectsRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids exposed (i.e. non-private) subjects.",
- recommended: false,
+ description: 'Disallow public and protected subjects.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Subject '{{subject}}' must be private.",
+ forbidden: 'Subject \'{{subject}}\' must be private.',
forbiddenAllowProtected:
- "Subject '{{subject}}' must be private or protected.",
+ 'Subject \'{{subject}}\' must be private or protected.',
},
schema: [
{
properties: {
- allowProtected: { type: "boolean" },
+ allowProtected: { type: 'boolean', description: 'Allow protected subjects.', default: false },
},
- type: "object",
+ type: 'object',
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-exposed-subjects",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-exposed-subjects',
+ create: (context) => {
const [config = {}] = context.options;
const { allowProtected = false } = config;
const { couldBeSubject, couldBeType } = getTypeServices(context);
- const messageId = allowProtected ? "forbiddenAllowProtected" : "forbidden";
+ const messageId = allowProtected ? 'forbiddenAllowProtected' : 'forbidden';
const accessibilityRexExp = allowProtected
? /^(private|protected)$/
: /^private$/;
@@ -55,7 +49,7 @@ const rule = ruleCreator({
return {
[`PropertyDefinition[accessibility!=${accessibilityRexExp}]`]: (
- node: es.PropertyDefinition
+ node: es.PropertyDefinition,
) => {
if (isSubject(node)) {
const { key } = node;
@@ -104,7 +98,7 @@ const rule = ruleCreator({
},
[`MethodDefinition[accessibility!=${accessibilityRexExp}][kind='method']`]:
(node: es.MethodDefinition) => {
- const functionExpression = node.value as any;
+ const functionExpression = node.value;
const returnType = functionExpression.returnType;
if (!returnType) {
return;
@@ -129,5 +123,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-finnish.ts b/src/rules/no-finnish.ts
new file mode 100644
index 00000000..f14271b8
--- /dev/null
+++ b/src/rules/no-finnish.ts
@@ -0,0 +1,111 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import {
+ getLoc,
+ getTypeServices,
+} from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noFinnishRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow Finnish notation.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Finnish notation is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-finnish',
+ create: (context) => {
+ const { esTreeNodeToTSNodeMap } = ESLintUtils.getParserServices(context);
+ const { couldBeObservable, couldReturnObservable }
+ = getTypeServices(context);
+
+ function checkNode(nameNode: es.Node, typeNode?: es.Node) {
+ if (
+ couldBeObservable(typeNode ?? nameNode)
+ || couldReturnObservable(typeNode ?? nameNode)
+ ) {
+ const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
+ if (/[$]+$/.test(tsNode.getText())) {
+ context.report({
+ loc: getLoc(tsNode),
+ messageId: 'forbidden',
+ });
+ }
+ }
+ }
+
+ return {
+ 'ArrayPattern > Identifier[name=/[$]+$/]': (node: es.Identifier) => {
+ checkNode(node);
+ },
+ 'ArrowFunctionExpression > Identifier[name=/[$]+$/]': (
+ node: es.Identifier,
+ ) => {
+ const parent = node.parent as es.ArrowFunctionExpression;
+ if (node !== parent.body) {
+ checkNode(node);
+ }
+ },
+ 'PropertyDefinition[key.name=/[$]+$/] > Identifier': (
+ node: es.Identifier,
+ ) => { checkNode(node, node.parent); },
+ 'FunctionDeclaration > Identifier[name=/[$]+$/]': (
+ node: es.Identifier,
+ ) => {
+ const parent = node.parent as es.FunctionDeclaration;
+ if (node === parent.id) {
+ checkNode(node, parent);
+ } else {
+ checkNode(node);
+ }
+ },
+ 'FunctionExpression > Identifier[name=/[$]+$/]': (
+ node: es.Identifier,
+ ) => {
+ const parent = node.parent as es.FunctionExpression;
+ if (node === parent.id) {
+ checkNode(node, parent);
+ } else {
+ checkNode(node);
+ }
+ },
+ 'MethodDefinition[key.name=/[$]+$/]': (node: es.MethodDefinition) => {
+ checkNode(node.key, node);
+ },
+ 'ObjectExpression > Property[computed=false][key.name=/[$]+$/]': (
+ node: es.Property,
+ ) => { checkNode(node.key); },
+ 'ObjectPattern > Property[value.name=/[$]+$/]': (node: es.Property) => {
+ checkNode(node.value);
+ },
+ 'TSCallSignatureDeclaration > Identifier[name=/[$]+$/]': (
+ node: es.Node,
+ ) => { checkNode(node); },
+ 'TSConstructSignatureDeclaration > Identifier[name=/[$]+$/]': (
+ node: es.Node,
+ ) => { checkNode(node); },
+ 'TSParameterProperty > Identifier[name=/[$]+$/]': (node: es.Identifier) => {
+ checkNode(node);
+ },
+ 'TSPropertySignature > Identifier[name=/[$]+$/]': (node: es.Identifier) => {
+ checkNode(node, node.parent);
+ },
+ 'TSMethodSignature > Identifier[name=/[$]+$/]': (node: es.Identifier) => {
+ const parent = node.parent as es.TSMethodSignature;
+ if (node === parent.key) {
+ checkNode(node, parent);
+ } else {
+ checkNode(node);
+ }
+ },
+ 'VariableDeclarator[id.name=/[$]+$/]': (node: es.VariableDeclarator) => {
+ checkNode(node.id, node.init ?? node);
+ },
+ };
+ },
+});
diff --git a/src/rules/no-floating-observables.ts b/src/rules/no-floating-observables.ts
new file mode 100644
index 00000000..569354ec
--- /dev/null
+++ b/src/rules/no-floating-observables.ts
@@ -0,0 +1,97 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices, isCallExpression, isChainExpression, isUnaryExpression } from '../etc';
+import { ruleCreator } from '../utils';
+
+const defaultOptions: readonly {
+ ignoreVoid?: boolean;
+}[] = [];
+
+const messageBase
+ = 'Observables must be subscribed to, returned, converted to a promise and awaited, '
+ + 'or be explicitly marked as ignored with the `void` operator.';
+
+const messageBaseNoVoid
+ = 'Observables must be subscribed to, returned, or converted to a promise and awaited.';
+
+export const noFloatingObservablesRule = ruleCreator({
+ defaultOptions,
+ meta: {
+ docs: {
+ description: 'Require Observables to be handled appropriately.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: messageBase,
+ forbiddenNoVoid: messageBaseNoVoid,
+ },
+ schema: [
+ {
+ properties: {
+ ignoreVoid: { type: 'boolean', default: true, description: 'Whether to ignore `void` expressions.' },
+ },
+ type: 'object',
+ },
+ ],
+ type: 'problem',
+ },
+ name: 'no-floating-observables',
+ create: (context) => {
+ const { couldBeObservable } = getTypeServices(context);
+ const [config = {}] = context.options;
+ const { ignoreVoid = true } = config;
+
+ function checkNode(node: es.CallExpression) {
+ if (couldBeObservable(node)) {
+ context.report({
+ messageId: ignoreVoid ? 'forbidden' : 'forbiddenNoVoid',
+ node,
+ });
+ }
+ }
+
+ function checkVoid(node: es.UnaryExpression) {
+ if (ignoreVoid) return;
+ if (node.operator !== 'void') return;
+
+ let expression = node.argument;
+ if (isChainExpression(expression)) {
+ expression = expression.expression;
+ }
+
+ if (!isCallExpression(expression)) return;
+ checkNode(expression);
+ }
+
+ return {
+ 'ExpressionStatement > CallExpression': (node: es.CallExpression) => {
+ checkNode(node);
+ },
+ 'ExpressionStatement > UnaryExpression': (node: es.UnaryExpression) => {
+ checkVoid(node);
+ },
+ 'ExpressionStatement > ChainExpression': (node: es.ChainExpression) => {
+ if (!isCallExpression(node.expression)) return;
+
+ checkNode(node.expression);
+ },
+ 'ExpressionStatement > SequenceExpression': (node: es.SequenceExpression) => {
+ node.expressions.forEach(expression => {
+ if (isCallExpression(expression)) {
+ checkNode(expression);
+ }
+ });
+ },
+ 'ExpressionStatement > ArrayExpression': (node: es.ArrayExpression) => {
+ node.elements.forEach(expression => {
+ if (!expression) return;
+ if (isCallExpression(expression)) {
+ checkNode(expression);
+ } else if (isUnaryExpression(expression)) {
+ checkVoid(expression);
+ }
+ });
+ },
+ };
+ },
+});
diff --git a/src/rules/no-ignored-default-value.ts b/src/rules/no-ignored-default-value.ts
new file mode 100644
index 00000000..9e8a6a53
--- /dev/null
+++ b/src/rules/no-ignored-default-value.ts
@@ -0,0 +1,113 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import { getTypeServices, isIdentifier, isMemberExpression, isObjectExpression, isProperty } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredDefaultValueRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Not specifying a default value is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-default-value',
+ create: (context) => {
+ const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+
+ function checkConfigObj(configArg: es.ObjectExpression) {
+ if (!configArg.properties.some(p => isProperty(p) && isIdentifier(p.key) && p.key.name === 'defaultValue')) {
+ context.report({
+ messageId: 'forbidden',
+ node: configArg,
+ });
+ }
+ }
+
+ function checkConfigType(configArg: es.Node) {
+ const configArgType = getTypeAtLocation(configArg);
+ if (!configArgType?.getProperties().some(p => p.name === 'defaultValue')) {
+ context.report({
+ messageId: 'forbidden',
+ node: configArg,
+ });
+ }
+ }
+
+ function checkArg(arg: es.Node) {
+ if (isIdentifier(arg)) {
+ checkConfigType(arg);
+ return;
+ } else if (isMemberExpression(arg) && isIdentifier(arg.property)) {
+ checkConfigType(arg.property);
+ return;
+ }
+ if (!isObjectExpression(arg)) {
+ return;
+ }
+ checkConfigObj(arg);
+ }
+
+ function checkFunctionArgs(node: es.Node, args: es.CallExpressionArgument[]) {
+ if (!couldBeType(node, 'firstValueFrom', { name: /[/\\]rxjs[/\\]/ })
+ && !couldBeType(node, 'lastValueFrom', { name: /[/\\]rxjs[/\\]/ })) {
+ return;
+ }
+ if (!args || args.length <= 0) {
+ return;
+ }
+ const [observableArg, configArg] = args;
+ if (!couldBeObservable(observableArg)) {
+ return;
+ }
+ if (!configArg) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ return;
+ }
+ checkArg(configArg);
+ }
+
+ function checkOperatorArgs(node: es.Node, args: es.CallExpressionArgument[]) {
+ if (!couldBeType(node, 'first', { name: /[/\\]rxjs[/\\]/ })
+ && !couldBeType(node, 'last', { name: /[/\\]rxjs[/\\]/ })) {
+ return;
+ }
+
+ if (!args || args.length <= 0) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ return;
+ }
+ const [arg] = args;
+ checkArg(arg);
+ }
+
+ return {
+ 'CallExpression[callee.name=/^(firstValueFrom|lastValueFrom)$/]': (node: es.CallExpression) => {
+ checkFunctionArgs(node.callee, node.arguments);
+ },
+ 'CallExpression[callee.property.name=/^(firstValueFrom|lastValueFrom)$/]': (node: es.CallExpression) => {
+ const memberExpression = node.callee as es.MemberExpression;
+ checkFunctionArgs(memberExpression.property, node.arguments);
+ },
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.name=/^(first|last)$/]': (node: es.CallExpression) => {
+ checkOperatorArgs(node.callee, node.arguments);
+ },
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.property.name=/^(first|last)$/]': (node: es.CallExpression) => {
+ const memberExpression = node.callee as es.MemberExpression;
+ checkOperatorArgs(memberExpression.property, node.arguments);
+ },
+ };
+ },
+});
diff --git a/src/rules/no-ignored-error.ts b/src/rules/no-ignored-error.ts
new file mode 100644
index 00000000..0a5a7cbf
--- /dev/null
+++ b/src/rules/no-ignored-error.ts
@@ -0,0 +1,84 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import { getTypeServices, isIdentifier, isMemberExpression, isObjectExpression, isProperty } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredErrorRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow calling `subscribe` without specifying an error handler.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Calling subscribe without an error handler is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-error',
+ create: (context) => {
+ const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
+ const { couldBeObservable, couldBeFunction } = getTypeServices(context);
+
+ function isMissingErrorCallback(callExpression: es.CallExpression): boolean {
+ if (callExpression.arguments.length >= 2) {
+ return false;
+ }
+ return couldBeFunction(callExpression.arguments[0]);
+ }
+
+ function isObjMissingError(arg: es.ObjectExpression): boolean {
+ return !arg.properties.some(
+ property =>
+ isProperty(property)
+ && isIdentifier(property.key)
+ && property.key.name === 'error',
+ );
+ }
+
+ function isTypeMissingError(arg: es.Identifier): boolean {
+ const argType = getTypeAtLocation(arg);
+ return !argType?.getProperties().some(p => p.name === 'error');
+ }
+
+ function isMissingErrorProperty(callExpression: es.CallExpression): boolean {
+ if (callExpression.arguments.length !== 1) {
+ return false;
+ }
+
+ const [arg] = callExpression.arguments;
+
+ if (isObjectExpression(arg)) {
+ return isObjMissingError(arg);
+ }
+ if (isIdentifier(arg)) {
+ return isTypeMissingError(arg);
+ }
+ if (isMemberExpression(arg) && isIdentifier(arg.property)) {
+ return isTypeMissingError(arg.property);
+ }
+ return false;
+ }
+
+ return {
+ 'CallExpression[arguments.length > 0] > MemberExpression > Identifier[name=\'subscribe\']':
+ (node: es.Identifier) => {
+ const memberExpression = node.parent as es.MemberExpression;
+ const callExpression = memberExpression.parent as es.CallExpression;
+
+ if (
+ (isMissingErrorCallback(callExpression)
+ || isMissingErrorProperty(callExpression))
+ && couldBeObservable(memberExpression.object)
+ ) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/source/rules/no-ignored-notifier.ts b/src/rules/no-ignored-notifier.ts
similarity index 61%
rename from source/rules/no-ignored-notifier.ts
rename to src/rules/no-ignored-notifier.ts
index 944abb94..6bea60ba 100644
--- a/source/rules/no-ignored-notifier.ts
+++ b/src/rules/no-ignored-notifier.ts
@@ -1,41 +1,35 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
+import { TSESTree as es } from '@typescript-eslint/utils';
import {
getTypeServices,
isArrowFunctionExpression,
isFunctionExpression,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+} from '../etc';
+import { ruleCreator } from '../utils';
-const rule = ruleCreator({
+export const noIgnoredNotifierRule = ruleCreator({
defaultOptions: [],
meta: {
docs: {
description:
- "Forbids observables not composed from the `repeatWhen` or `retryWhen` notifier.",
- recommended: "error",
+ 'Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Ignoring the notifier is forbidden.",
+ forbidden: 'Ignoring the notifier is forbidden.',
},
schema: [],
- type: "problem",
+ type: 'problem',
},
- name: "no-ignored-notifier",
+ name: 'no-ignored-notifier',
create: (context) => {
const { couldBeMonoTypeOperatorFunction } = getTypeServices(context);
- type Entry = {
+ interface Entry {
node: es.Node;
param: es.Identifier;
sightings: number;
- };
+ }
const entries: Entry[] = [];
function getEntry() {
@@ -44,8 +38,8 @@ const rule = ruleCreator({
}
return {
- "CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]": (
- node: es.CallExpression
+ 'CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]': (
+ node: es.CallExpression,
) => {
if (couldBeMonoTypeOperatorFunction(node)) {
const [arg] = node.arguments;
@@ -59,15 +53,15 @@ const rule = ruleCreator({
});
} else {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: node.callee,
});
}
}
}
},
- "CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]:exit": (
- node: es.CallExpression
+ 'CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]:exit': (
+ node: es.CallExpression,
) => {
const entry = getEntry();
if (!entry) {
@@ -76,14 +70,14 @@ const rule = ruleCreator({
if (entry.node === node) {
if (entry.sightings < 2) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: node.callee,
});
}
entries.pop();
}
},
- Identifier: (node: es.Identifier) => {
+ 'Identifier': (node: es.Identifier) => {
const entry = getEntry();
if (!entry) {
return;
@@ -95,5 +89,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-ignored-replay-buffer.ts b/src/rules/no-ignored-replay-buffer.ts
new file mode 100644
index 00000000..4b5d4412
--- /dev/null
+++ b/src/rules/no-ignored-replay-buffer.ts
@@ -0,0 +1,81 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { isIdentifier, isObjectExpression, isProperty } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredReplayBufferRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.',
+ recommended: 'recommended',
+ },
+ messages: {
+ forbidden: 'Ignoring the buffer size is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-replay-buffer',
+ create: (context) => {
+ function checkShareReplayConfig(
+ node: es.Identifier,
+ shareReplayConfigArg: es.ObjectExpression,
+ ) {
+ if (!shareReplayConfigArg.properties.some(p => isProperty(p) && isIdentifier(p.key) && p.key.name === 'bufferSize')) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+ }
+
+ function checkNode(
+ node: es.Identifier,
+ { arguments: args }: es.NewExpression | es.CallExpression,
+ ) {
+ if (!args || args.length === 0) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+
+ if (node.name === 'shareReplay' && args?.length === 1) {
+ const [arg] = args;
+ if (isObjectExpression(arg)) {
+ checkShareReplayConfig(node, arg);
+ }
+ }
+ }
+
+ return {
+ 'NewExpression > Identifier[name=\'ReplaySubject\']': (
+ node: es.Identifier,
+ ) => {
+ const newExpression = node.parent as es.NewExpression;
+ checkNode(node, newExpression);
+ },
+ 'NewExpression > MemberExpression > Identifier[name=\'ReplaySubject\']': (
+ node: es.Identifier,
+ ) => {
+ const memberExpression = node.parent as es.MemberExpression;
+ const newExpression = memberExpression.parent as es.NewExpression;
+ checkNode(node, newExpression);
+ },
+ 'CallExpression > Identifier[name=/^(publishReplay|shareReplay)$/]': (
+ node: es.Identifier,
+ ) => {
+ const callExpression = node.parent as es.CallExpression;
+ checkNode(node, callExpression);
+ },
+ 'CallExpression > MemberExpression > Identifier[name=/^(publishReplay|shareReplay)$/]': (
+ node: es.Identifier,
+ ) => {
+ const memberExpression = node.parent as es.MemberExpression;
+ const callExpression = memberExpression.parent as es.CallExpression;
+ checkNode(node, callExpression);
+ },
+ };
+ },
+});
diff --git a/src/rules/no-ignored-subscribe.ts b/src/rules/no-ignored-subscribe.ts
new file mode 100644
index 00000000..a885df11
--- /dev/null
+++ b/src/rules/no-ignored-subscribe.ts
@@ -0,0 +1,39 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredSubscribeRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow calling `subscribe` without specifying arguments.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Calling subscribe without arguments is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-subscribe',
+ create: (context) => {
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+
+ return {
+ 'CallExpression[arguments.length = 0][callee.property.name=\'subscribe\']':
+ (node: es.CallExpression) => {
+ const callee = node.callee as es.MemberExpression;
+ if (
+ couldBeObservable(callee.object)
+ || couldBeType(callee.object, 'Subscribable')
+ ) {
+ context.report({
+ messageId: 'forbidden',
+ node: callee.property,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-ignored-subscription.ts b/src/rules/no-ignored-subscription.ts
new file mode 100644
index 00000000..0116c461
--- /dev/null
+++ b/src/rules/no-ignored-subscription.ts
@@ -0,0 +1,41 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredSubscriptionRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow ignoring the subscription returned by `subscribe`.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Ignoring returned subscriptions is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-subscription',
+ create: (context) => {
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+
+ return {
+ 'ExpressionStatement > CallExpression > MemberExpression[property.name=\'subscribe\']':
+ (node: es.MemberExpression) => {
+ if (couldBeObservable(node.object)) {
+ const callExpression = node.parent as es.CallExpression;
+ if (
+ callExpression.arguments.length === 1
+ && couldBeType(callExpression.arguments[0], 'Subscriber')
+ ) {
+ return;
+ }
+ context.report({
+ messageId: 'forbidden',
+ node: node.property,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-ignored-takewhile-value.ts b/src/rules/no-ignored-takewhile-value.ts
new file mode 100644
index 00000000..025381b0
--- /dev/null
+++ b/src/rules/no-ignored-takewhile-value.ts
@@ -0,0 +1,65 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import {
+ isArrayPattern,
+ isIdentifier,
+ isImport,
+ isObjectPattern,
+} from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noIgnoredTakewhileValueRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow ignoring the value within `takeWhile`.',
+ recommended: 'recommended',
+ },
+ messages: {
+ forbidden: 'Ignoring the value within takeWhile is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-ignored-takewhile-value',
+ create: (context) => {
+ function checkNode(
+ expression: es.ArrowFunctionExpression | es.FunctionExpression,
+ ) {
+ const scope = context.sourceCode.getScope(expression);
+ if (!isImport(scope, 'takeWhile', /^rxjs\/?/)) {
+ return;
+ }
+ let ignored = true;
+ const [param] = expression.params;
+ if (param) {
+ if (isIdentifier(param)) {
+ const variable = scope.variables.find(
+ ({ name }) => name === param.name,
+ );
+ if (variable && variable.references.length > 0) {
+ ignored = false;
+ }
+ } else if (isArrayPattern(param)) {
+ ignored = false;
+ } else if (isObjectPattern(param)) {
+ ignored = false;
+ }
+ }
+ if (ignored) {
+ context.report({
+ messageId: 'forbidden',
+ node: expression,
+ });
+ }
+ }
+
+ return {
+ 'CallExpression[callee.name=\'takeWhile\'] > ArrowFunctionExpression': (
+ node: es.ArrowFunctionExpression,
+ ) => { checkNode(node); },
+ 'CallExpression[callee.name=\'takeWhile\'] > FunctionExpression': (
+ node: es.FunctionExpression,
+ ) => { checkNode(node); },
+ };
+ },
+});
diff --git a/source/rules/no-implicit-any-catch.ts b/src/rules/no-implicit-any-catch.ts
similarity index 58%
rename from source/rules/no-implicit-any-catch.ts
rename to src/rules/no-implicit-any-catch.ts
index 48c2cf8d..63ef42e4 100644
--- a/source/rules/no-implicit-any-catch.ts
+++ b/src/rules/no-implicit-any-catch.ts
@@ -1,13 +1,8 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
import {
AST_NODE_TYPES,
- TSESLint as eslint,
TSESTree as es,
-} from "@typescript-eslint/experimental-utils";
+ TSESLint as eslint,
+} from '@typescript-eslint/utils';
import {
getTypeServices,
hasTypeAnnotation,
@@ -16,23 +11,22 @@ import {
isIdentifier,
isMemberExpression,
isObjectExpression,
- isProperty,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+ isProperty } from '../etc';
+import { ruleCreator } from '../utils';
function isParenthesised(
sourceCode: Readonly,
- node: es.Node
+ node: es.Node,
) {
const before = sourceCode.getTokenBefore(node);
const after = sourceCode.getTokenAfter(node);
return (
- before &&
- after &&
- before.value === "(" &&
- before.range[1] <= node.range[0] &&
- after.value === ")" &&
- after.range[0] >= node.range[1]
+ before
+ && after
+ && before.value === '('
+ && before.range[1] <= node.range[0]
+ && after.value === ')'
+ && after.range[0] >= node.range[1]
);
}
@@ -40,48 +34,55 @@ const defaultOptions: readonly {
allowExplicitAny?: boolean;
}[] = [];
-const rule = ruleCreator({
+export const noImplicitAnyCatchRule = ruleCreator({
defaultOptions,
meta: {
docs: {
description:
- "Forbids implicit `any` error parameters in `catchError` operators.",
- recommended: "error",
- suggestion: true,
+ 'Disallow implicit `any` error parameters in `catchError` operators.',
+ recommended: {
+ recommended: true,
+ strict: [{
+ allowExplicitAny: false,
+ }],
+ },
+ requiresTypeChecking: true,
},
- fixable: "code",
+ fixable: 'code',
hasSuggestions: true,
messages: {
- explicitAny: "Explicit `any` in `catchError`.",
- implicitAny: "Implicit `any` in `catchError`.",
- narrowed: "Error type must be `unknown` or `any`.",
+ explicitAny: 'Explicit `any` in `catchError`.',
+ implicitAny: 'Implicit `any` in `catchError`.',
+ narrowed: 'Error type must be `unknown` or `any`.',
suggestExplicitUnknown:
- "Use `unknown` instead, this will force you to explicitly and safely assert the type is correct.",
+ 'Use `unknown` instead, this will force you to explicitly and safely assert the type is correct.',
},
schema: [
{
additionalProperties: false,
properties: {
allowExplicitAny: {
- type: "boolean",
+ type: 'boolean',
+ description: 'Allow error variable to be explicitly typed as `any`.',
+ default: true,
},
},
- type: "object",
+ type: 'object',
},
],
- type: "suggestion",
+ type: 'suggestion',
},
- name: "no-implicit-any-catch",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-implicit-any-catch',
+ create: (context) => {
const [config = {}] = context.options;
- const { allowExplicitAny = false } = config;
+ const { allowExplicitAny = true } = config;
const { couldBeObservable } = getTypeServices(context);
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
function checkCallback(callback: es.Node) {
if (
- isArrowFunctionExpression(callback) ||
- isFunctionExpression(callback)
+ isArrowFunctionExpression(callback)
+ || isFunctionExpression(callback)
) {
const [param] = callback.params;
if (!param) {
@@ -97,29 +98,29 @@ const rule = ruleCreator({
return;
}
function fix(fixer: eslint.RuleFixer) {
- return fixer.replaceText(typeAnnotation, ": unknown");
+ return fixer.replaceText(typeAnnotation, ': unknown');
}
context.report({
fix,
- messageId: "explicitAny",
+ messageId: 'explicitAny',
node: param,
suggest: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
fix,
},
],
});
} else if (type !== AST_NODE_TYPES.TSUnknownKeyword) {
function fix(fixer: eslint.RuleFixer) {
- return fixer.replaceText(typeAnnotation, ": unknown");
+ return fixer.replaceText(typeAnnotation, ': unknown');
}
context.report({
- messageId: "narrowed",
+ messageId: 'narrowed',
node: param,
suggest: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
fix,
},
],
@@ -128,20 +129,20 @@ const rule = ruleCreator({
} else {
function fix(fixer: eslint.RuleFixer) {
if (isParenthesised(sourceCode, param)) {
- return fixer.insertTextAfter(param, ": unknown");
+ return fixer.insertTextAfter(param, ': unknown');
}
return [
- fixer.insertTextBefore(param, "("),
- fixer.insertTextAfter(param, ": unknown)"),
+ fixer.insertTextBefore(param, '('),
+ fixer.insertTextAfter(param, ': unknown)'),
];
}
context.report({
fix,
- messageId: "implicitAny",
+ messageId: 'implicitAny',
node: param,
suggest: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
fix,
},
],
@@ -151,14 +152,14 @@ const rule = ruleCreator({
}
return {
- "CallExpression[callee.name='catchError']": (node: es.CallExpression) => {
+ 'CallExpression[callee.name=\'catchError\']': (node: es.CallExpression) => {
const [callback] = node.arguments;
if (!callback) {
return;
}
checkCallback(callback);
},
- "CallExpression[callee.property.name='subscribe'],CallExpression[callee.name='tap']":
+ 'CallExpression[callee.property.name=\'subscribe\'],CallExpression[callee.name=\'tap\']':
(node: es.CallExpression) => {
const { callee } = node;
if (isMemberExpression(callee) && !couldBeObservable(callee.object)) {
@@ -170,9 +171,9 @@ const rule = ruleCreator({
} else if (observer && isObjectExpression(observer)) {
const errorProperty = observer.properties.find(
(property) =>
- isProperty(property) &&
- isIdentifier(property.key) &&
- property.key.name === "error"
+ isProperty(property)
+ && isIdentifier(property.key)
+ && property.key.name === 'error',
) as es.Property;
if (errorProperty) {
checkCallback(errorProperty.value);
@@ -182,5 +183,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-index.ts b/src/rules/no-index.ts
new file mode 100644
index 00000000..aa33acef
--- /dev/null
+++ b/src/rules/no-index.ts
@@ -0,0 +1,29 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
+
+export const noIndexRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow importing index modules.',
+ recommended: 'recommended',
+ },
+ messages: {
+ forbidden: 'RxJS imports from index modules are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-index',
+ create: (context) => {
+ return {
+ [String.raw`ImportDeclaration Literal[value=/^rxjs(?:\u002f\w+)?\u002findex/]`]:
+ (node: es.Literal) => {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ },
+ };
+ },
+});
diff --git a/source/rules/no-internal.ts b/src/rules/no-internal.ts
similarity index 67%
rename from source/rules/no-internal.ts
rename to src/rules/no-internal.ts
index 866c5379..2789fdd9 100644
--- a/source/rules/no-internal.ts
+++ b/src/rules/no-internal.ts
@@ -1,34 +1,29 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
import {
TSESTree as es,
TSESLint as eslint,
-} from "@typescript-eslint/experimental-utils";
-import { ruleCreator } from "../utils";
+} from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
-const rule = ruleCreator({
+export const noInternalRule = ruleCreator({
defaultOptions: [],
meta: {
docs: {
- description: "Forbids the importation of internals.",
- recommended: "error",
+ description: 'Disallow importing internal modules.',
+ recommended: 'recommended',
},
- fixable: "code",
+ fixable: 'code',
hasSuggestions: true,
messages: {
- forbidden: "RxJS imports from internal are forbidden.",
- suggest: "Import from a non-internal location.",
+ forbidden: 'RxJS imports from internal are forbidden.',
+ suggest: 'Import from a non-internal location.',
},
schema: [],
- type: "problem",
+ type: 'problem',
},
- name: "no-internal",
+ name: 'no-internal',
create: (context) => {
function getReplacement(location: string) {
- const match = location.match(/^\s*('|")/);
+ const match = /^\s*('|")/.exec(location);
if (!match) {
return undefined;
}
@@ -62,22 +57,23 @@ const rule = ruleCreator({
return {
[String.raw`ImportDeclaration Literal[value=/^rxjs\u002finternal/]`]: (
- node: es.Literal
+ node: es.Literal,
) => {
const replacement = getReplacement(node.raw);
if (replacement) {
function fix(fixer: eslint.RuleFixer) {
- return fixer.replaceText(node, replacement as string);
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ return fixer.replaceText(node, replacement!);
}
context.report({
fix,
- messageId: "forbidden",
+ messageId: 'forbidden',
node,
- suggest: [{ fix, messageId: "suggest" }],
+ suggest: [{ fix, messageId: 'suggest' }],
});
} else {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node,
});
}
@@ -85,5 +81,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-misused-observables.ts b/src/rules/no-misused-observables.ts
new file mode 100644
index 00000000..4754ab35
--- /dev/null
+++ b/src/rules/no-misused-observables.ts
@@ -0,0 +1,514 @@
+import { AST_NODE_TYPES, TSESTree as es, TSESLint as eslint, ESLintUtils } from '@typescript-eslint/utils';
+import * as tsutils from 'ts-api-utils';
+import ts from 'typescript';
+import {
+ getTypeServices,
+ isArrowFunctionExpression,
+ isFunctionDeclaration,
+ isFunctionExpression,
+ isJSXExpressionContainer,
+ isMethodDefinition,
+ isPropertyDefinition,
+} from '../etc';
+import { ruleCreator } from '../utils';
+
+// The implementation of this rule is similar to typescript-eslint's no-misused-promises. MIT License.
+// https://github.com/typescript-eslint/typescript-eslint/blob/fcd6cf063a774f73ea00af23705117a197f826d4/packages/eslint-plugin/src/rules/no-misused-promises.ts
+
+// This is only exported for dts build to work.
+export interface ChecksVoidReturnOptions {
+ arguments?: boolean;
+ attributes?: boolean;
+ inheritedMethods?: boolean;
+ properties?: boolean;
+ returns?: boolean;
+ variables?: boolean;
+}
+
+function parseChecksVoidReturn(
+ checksVoidReturn: boolean | ChecksVoidReturnOptions,
+): ChecksVoidReturnOptions | false {
+ switch (checksVoidReturn) {
+ case false:
+ return false;
+
+ case true:
+ case undefined:
+ return {
+ arguments: true,
+ attributes: true,
+ inheritedMethods: true,
+ properties: true,
+ returns: true,
+ variables: true,
+ };
+
+ default:
+ return {
+ arguments: checksVoidReturn.arguments ?? true,
+ attributes: checksVoidReturn.attributes ?? true,
+ inheritedMethods: checksVoidReturn.inheritedMethods ?? true,
+ properties: checksVoidReturn.properties ?? true,
+ returns: checksVoidReturn.returns ?? true,
+ variables: checksVoidReturn.variables ?? true,
+ };
+ }
+}
+
+const defaultOptions: readonly {
+ checksVoidReturn?: boolean | ChecksVoidReturnOptions;
+ checksSpreads?: boolean;
+}[] = [];
+
+export const noMisusedObservablesRule = ruleCreator({
+ defaultOptions,
+ meta: {
+ docs: {
+ description: 'Disallow Observables in places not designed to handle them.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbiddenVoidReturnArgument: 'Observable returned in function argument where a void return was expected.',
+ forbiddenVoidReturnAttribute: 'Observable-returning function provided to attribute where a void return was expected.',
+ forbiddenVoidReturnInheritedMethod: 'Observable-returning method provided where a void return was expected by extended/implemented type \'{{heritageTypeName}}\'.',
+ forbiddenVoidReturnProperty: 'Observable-returning function provided to property where a void return was expected.',
+ forbiddenVoidReturnReturnValue: 'Observable-returning function provided to return value where a void return was expected.',
+ forbiddenVoidReturnVariable: 'Observable-returning function provided to variable where a void return was expected.',
+ forbiddenSpread: 'Expected a non-Observable value to be spread into an object.',
+ },
+ schema: [
+ {
+ properties: {
+ checksVoidReturn: {
+ default: true,
+ description: 'Disallow returning an Observable from a function typed as returning `void`.',
+ oneOf: [
+ {
+ default: true,
+ type: 'boolean',
+ description: 'Disallow returning an Observable from all types of functions typed as returning `void`.',
+ },
+ {
+ type: 'object',
+ additionalProperties: false,
+ description: 'Which forms of functions may have checking disabled.',
+ properties: {
+ arguments: { type: 'boolean', description: 'Disallow passing an Observable-returning function as an argument where the parameter type expects a function that returns `void`.' },
+ attributes: { type: 'boolean', description: 'Disallow passing an Observable-returning function as a JSX attribute expected to be a function that returns `void`.' },
+ inheritedMethods: { type: 'boolean', description: 'Disallow providing an Observable-returning function where a function that returns `void` is expected by an extended or implemented type.' },
+ properties: { type: 'boolean', description: 'Disallow providing an Observable-returning function where a function that returns `void` is expected by a property.' },
+ returns: { type: 'boolean', description: 'Disallow returning an Observable-returning function where a function that returns `void` is expected.' },
+ variables: { type: 'boolean', description: 'Disallow assigning or declaring an Observable-returning function where a function that returns `void` is expected.' },
+ },
+ },
+ ],
+ },
+ checksSpreads: { type: 'boolean', default: true, description: 'Disallow `...` spreading an Observable.' },
+ },
+ type: 'object',
+ },
+ ],
+ type: 'problem',
+ },
+ name: 'no-misused-observables',
+ create: (context) => {
+ const { program, esTreeNodeToTSNodeMap, getTypeAtLocation } = ESLintUtils.getParserServices(context);
+ const checker = program.getTypeChecker();
+ const { couldBeObservable, couldReturnObservable } = getTypeServices(context);
+ const [config = {}] = context.options;
+ const { checksVoidReturn = true, checksSpreads = true } = config;
+
+ const parsedChecksVoidReturn = parseChecksVoidReturn(checksVoidReturn);
+
+ const voidReturnChecks: eslint.RuleListener = parsedChecksVoidReturn ? {
+ ...(parsedChecksVoidReturn.arguments && {
+ CallExpression: checkArguments,
+ NewExpression: checkArguments,
+ }),
+ ...(parsedChecksVoidReturn.attributes && {
+ JSXAttribute: checkJSXAttribute,
+ }),
+ ...(parsedChecksVoidReturn.inheritedMethods && {
+ ClassDeclaration: checkClassLikeOrInterfaceNode,
+ ClassExpression: checkClassLikeOrInterfaceNode,
+ TSInterfaceDeclaration: checkClassLikeOrInterfaceNode,
+ }),
+ ...(parsedChecksVoidReturn.properties && {
+ Property: checkProperty,
+ }),
+ ...(parsedChecksVoidReturn.returns && {
+ ReturnStatement: checkReturnStatement,
+ }),
+ ...(parsedChecksVoidReturn.variables && {
+ AssignmentExpression: checkAssignment,
+ VariableDeclarator: checkVariableDeclaration,
+ }),
+ } : {};
+
+ const spreadChecks: eslint.RuleListener = {
+ SpreadElement: (node) => {
+ if (couldBeObservable(node.argument)) {
+ context.report({
+ messageId: 'forbiddenSpread',
+ node: node.argument,
+ });
+ }
+ },
+ };
+
+ function checkArguments(node: es.CallExpression | es.NewExpression): void {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ const voidArgs = voidFunctionArguments(checker, tsNode);
+ if (!voidArgs.size) {
+ return;
+ }
+
+ for (const [index, argument] of node.arguments.entries()) {
+ if (!voidArgs.has(index)) {
+ continue;
+ }
+
+ if (couldReturnObservable(argument)) {
+ context.report({
+ messageId: 'forbiddenVoidReturnArgument',
+ node: argument,
+ });
+ }
+ }
+ }
+
+ function checkJSXAttribute(node: es.JSXAttribute): void {
+ if (!node.value || !isJSXExpressionContainer(node.value)) {
+ return;
+ }
+
+ if (couldReturnObservable(node.value.expression)) {
+ context.report({
+ messageId: 'forbiddenVoidReturnAttribute',
+ node: node.value,
+ });
+ }
+ }
+
+ function checkClassLikeOrInterfaceNode(
+ node: es.ClassDeclaration | es.ClassExpression | es.TSInterfaceDeclaration,
+ ): void {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+
+ const heritageTypes = getHeritageTypes(checker, tsNode);
+ if (!heritageTypes?.length) {
+ return;
+ }
+
+ for (const element of node.body.body) {
+ const tsElement = esTreeNodeToTSNodeMap.get(element);
+ const memberName = tsElement?.name?.getText();
+ if (memberName === undefined) {
+ // See comment in typescript-eslint no-misused-promises for why.
+ continue;
+ }
+
+ if (!couldReturnObservable(element)) {
+ continue;
+ }
+
+ if (isStaticMember(element)) {
+ continue;
+ }
+
+ for (const heritageType of heritageTypes) {
+ const heritageMember = getMemberIfExists(heritageType, memberName);
+ if (heritageMember === undefined) {
+ continue;
+ }
+ const memberType = checker.getTypeOfSymbolAtLocation(heritageMember, tsElement);
+ if (!isVoidReturningFunctionType(memberType)) {
+ continue;
+ }
+
+ context.report({
+ messageId: 'forbiddenVoidReturnInheritedMethod',
+ node: element,
+ data: { heritageTypeName: checker.typeToString(heritageType) },
+ });
+ }
+ }
+ }
+
+ function checkProperty(node: es.Property): void {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+
+ const contextualType = getPropertyContextualType(checker, tsNode);
+ if (contextualType === undefined) {
+ return;
+ }
+
+ if (!isVoidReturningFunctionType(contextualType)) {
+ return;
+ }
+ if (!couldReturnObservable(node.value)) {
+ return;
+ }
+
+ context.report({
+ messageId: 'forbiddenVoidReturnProperty',
+ node: node.value,
+ });
+ }
+
+ function checkReturnStatement(node: es.ReturnStatement): void {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ if (tsNode.expression === undefined || !node.argument) {
+ return;
+ }
+
+ // Optimization to avoid touching type info.
+ function getFunctionNode() {
+ let current: es.Node | undefined = node.parent;
+ while (
+ current
+ && !isArrowFunctionExpression(current)
+ && !isFunctionExpression(current)
+ && !isFunctionDeclaration(current)
+ ) {
+ current = current.parent;
+ }
+ return current;
+ }
+ const functionNode = getFunctionNode();
+ if (
+ functionNode?.returnType
+ && !isPossiblyFunctionType(functionNode.returnType)
+ ) {
+ return;
+ }
+
+ const contextualType = checker.getContextualType(tsNode.expression);
+ if (contextualType === undefined) {
+ return;
+ }
+ if (!isVoidReturningFunctionType(contextualType)) {
+ return;
+ }
+ if (!couldReturnObservable(node.argument)) {
+ return;
+ }
+
+ context.report({
+ node: node.argument,
+ messageId: 'forbiddenVoidReturnReturnValue',
+ });
+ }
+
+ function checkAssignment(node: es.AssignmentExpression): void {
+ const varType = getTypeAtLocation(node.left);
+ if (!isVoidReturningFunctionType(varType)) {
+ return;
+ }
+
+ if (couldReturnObservable(node.right)) {
+ context.report({
+ messageId: 'forbiddenVoidReturnVariable',
+ node: node.right,
+ });
+ }
+ }
+
+ function checkVariableDeclaration(node: es.VariableDeclarator): void {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ if (
+ tsNode.initializer === undefined
+ || !node.init
+ || !node.id.typeAnnotation
+ ) {
+ return;
+ }
+
+ // Optimization to avoid touching type info.
+ if (!isPossiblyFunctionType(node.id.typeAnnotation)) {
+ return;
+ }
+
+ const varType = getTypeAtLocation(node.id);
+ if (!isVoidReturningFunctionType(varType)) {
+ return;
+ }
+
+ if (couldReturnObservable(node.init)) {
+ context.report({
+ messageId: 'forbiddenVoidReturnVariable',
+ node: node.init,
+ });
+ }
+ }
+
+ return {
+ ...(checksVoidReturn ? voidReturnChecks : {}),
+ ...(checksSpreads ? spreadChecks : {}),
+ };
+ },
+});
+
+function voidFunctionArguments(
+ checker: ts.TypeChecker,
+ tsNode: ts.CallExpression | ts.NewExpression,
+): Set {
+ // let b = new Object;
+ if (!tsNode.arguments) {
+ return new Set();
+ }
+
+ const voidReturnIndices = new Set();
+ const type = checker.getTypeAtLocation(tsNode.expression);
+
+ for (const subType of tsutils.unionTypeParts(type)) {
+ const signatures = ts.isCallExpression(tsNode)
+ ? subType.getCallSignatures()
+ : subType.getConstructSignatures();
+ for (const signature of signatures) {
+ for (const [index, parameter] of signature.parameters.entries()) {
+ const type = checker.getTypeOfSymbolAtLocation(parameter, tsNode.expression);
+ if (isVoidReturningFunctionType(type)) {
+ voidReturnIndices.add(index);
+ }
+ }
+ }
+ }
+
+ return voidReturnIndices;
+}
+
+function isVoidReturningFunctionType(
+ type: ts.Type,
+): boolean {
+ let hasVoidReturn = false;
+
+ for (const subType of tsutils.unionTypeParts(type)) {
+ for (const signature of subType.getCallSignatures()) {
+ const returnType = signature.getReturnType();
+
+ hasVoidReturn ||= tsutils.isTypeFlagSet(returnType, ts.TypeFlags.Void);
+ }
+ }
+
+ return hasVoidReturn;
+}
+
+function getHeritageTypes(
+ checker: ts.TypeChecker,
+ tsNode: ts.ClassDeclaration | ts.ClassExpression | ts.InterfaceDeclaration,
+): ts.Type[] | undefined {
+ return tsNode.heritageClauses
+ ?.flatMap(clause => clause.types)
+ .map(typeExpressions => checker.getTypeAtLocation(typeExpressions));
+}
+
+function getMemberIfExists(
+ type: ts.Type,
+ memberName: string,
+): ts.Symbol | undefined {
+ const escapedMemberName = ts.escapeLeadingUnderscores(memberName);
+ const symbolMemberMatch = type.getSymbol()?.members?.get(escapedMemberName);
+ return symbolMemberMatch ?? tsutils.getPropertyOfType(type, escapedMemberName);
+}
+
+function isStaticMember(node: es.Node): boolean {
+ return (isMethodDefinition(node) || isPropertyDefinition(node))
+ && node.static;
+}
+
+function getPropertyContextualType(
+ checker: ts.TypeChecker,
+ tsNode: ts.Node,
+): ts.Type | undefined {
+ if (ts.isPropertyAssignment(tsNode)) {
+ // { a: 1 }
+ return checker.getContextualType(tsNode.initializer);
+ } else if (ts.isShorthandPropertyAssignment(tsNode)) {
+ // { a }
+ return checker.getContextualType(tsNode.name);
+ } else if (ts.isMethodDeclaration(tsNode)) {
+ // { a() {} }
+ if (ts.isComputedPropertyName(tsNode.name)) {
+ return;
+ }
+ const obj = tsNode.parent;
+ if (!ts.isObjectLiteralExpression(obj)) {
+ return;
+ }
+ const objType = checker.getContextualType(obj);
+ if (objType === undefined) {
+ return;
+ }
+ const propertySymbol = checker.getPropertyOfType(objType, tsNode.name.text);
+ if (propertySymbol === undefined) {
+ return;
+ }
+ return checker.getTypeOfSymbolAtLocation(propertySymbol, tsNode.name);
+ } else {
+ return undefined;
+ }
+}
+
+/**
+ * From no-misused-promises.
+ */
+function isPossiblyFunctionType(node: es.TSTypeAnnotation): boolean {
+ switch (node.typeAnnotation.type) {
+ case AST_NODE_TYPES.TSConditionalType:
+ case AST_NODE_TYPES.TSConstructorType:
+ case AST_NODE_TYPES.TSFunctionType:
+ case AST_NODE_TYPES.TSImportType:
+ case AST_NODE_TYPES.TSIndexedAccessType:
+ case AST_NODE_TYPES.TSInferType:
+ case AST_NODE_TYPES.TSIntersectionType:
+ case AST_NODE_TYPES.TSQualifiedName:
+ case AST_NODE_TYPES.TSThisType:
+ case AST_NODE_TYPES.TSTypeOperator:
+ case AST_NODE_TYPES.TSTypeQuery:
+ case AST_NODE_TYPES.TSTypeReference:
+ case AST_NODE_TYPES.TSUnionType:
+ return true;
+
+ case AST_NODE_TYPES.TSTypeLiteral:
+ return node.typeAnnotation.members.some(
+ member =>
+ member.type === AST_NODE_TYPES.TSCallSignatureDeclaration
+ || member.type === AST_NODE_TYPES.TSConstructSignatureDeclaration,
+ );
+
+ case AST_NODE_TYPES.TSAbstractKeyword:
+ case AST_NODE_TYPES.TSAnyKeyword:
+ case AST_NODE_TYPES.TSArrayType:
+ case AST_NODE_TYPES.TSAsyncKeyword:
+ case AST_NODE_TYPES.TSBigIntKeyword:
+ case AST_NODE_TYPES.TSBooleanKeyword:
+ case AST_NODE_TYPES.TSDeclareKeyword:
+ case AST_NODE_TYPES.TSExportKeyword:
+ case AST_NODE_TYPES.TSIntrinsicKeyword:
+ case AST_NODE_TYPES.TSLiteralType:
+ case AST_NODE_TYPES.TSMappedType:
+ case AST_NODE_TYPES.TSNamedTupleMember:
+ case AST_NODE_TYPES.TSNeverKeyword:
+ case AST_NODE_TYPES.TSNullKeyword:
+ case AST_NODE_TYPES.TSNumberKeyword:
+ case AST_NODE_TYPES.TSObjectKeyword:
+ case AST_NODE_TYPES.TSOptionalType:
+ case AST_NODE_TYPES.TSPrivateKeyword:
+ case AST_NODE_TYPES.TSProtectedKeyword:
+ case AST_NODE_TYPES.TSPublicKeyword:
+ case AST_NODE_TYPES.TSReadonlyKeyword:
+ case AST_NODE_TYPES.TSRestType:
+ case AST_NODE_TYPES.TSStaticKeyword:
+ case AST_NODE_TYPES.TSStringKeyword:
+ case AST_NODE_TYPES.TSSymbolKeyword:
+ case AST_NODE_TYPES.TSTemplateLiteralType:
+ case AST_NODE_TYPES.TSTupleType:
+ case AST_NODE_TYPES.TSTypePredicate:
+ case AST_NODE_TYPES.TSUndefinedKeyword:
+ case AST_NODE_TYPES.TSUnknownKeyword:
+ case AST_NODE_TYPES.TSVoidKeyword:
+ return false;
+ }
+}
diff --git a/src/rules/no-nested-subscribe.ts b/src/rules/no-nested-subscribe.ts
new file mode 100644
index 00000000..bd94d086
--- /dev/null
+++ b/src/rules/no-nested-subscribe.ts
@@ -0,0 +1,52 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noNestedSubscribeRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow calling `subscribe` within a `subscribe` callback.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Nested subscribe calls are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-nested-subscribe',
+ create: (context) => {
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+ const argumentsMap = new WeakMap();
+ return {
+ [`CallExpression > MemberExpression[property.name='subscribe']`]: (
+ node: es.MemberExpression,
+ ) => {
+ if (
+ !couldBeObservable(node.object)
+ && !couldBeType(node.object, 'Subscribable')
+ ) {
+ return;
+ }
+ const callExpression = node.parent as es.CallExpression;
+ let parent = callExpression.parent as es.Node | undefined;
+ while (parent) {
+ if (argumentsMap.has(parent)) {
+ context.report({
+ messageId: 'forbidden',
+ node: node.property,
+ });
+ return;
+ }
+ parent = parent.parent;
+ }
+ for (const arg of callExpression.arguments) {
+ argumentsMap.set(arg);
+ }
+ },
+ };
+ },
+});
diff --git a/source/rules/no-redundant-notify.ts b/src/rules/no-redundant-notify.ts
similarity index 66%
rename from source/rules/no-redundant-notify.ts
rename to src/rules/no-redundant-notify.ts
index 396c115a..f515f9e7 100644
--- a/source/rules/no-redundant-notify.ts
+++ b/src/rules/no-redundant-notify.ts
@@ -1,47 +1,40 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
import {
- TSESLint as eslint,
TSESTree as es,
-} from "@typescript-eslint/experimental-utils";
+ TSESLint as eslint,
+} from '@typescript-eslint/utils';
import {
- getParent,
getTypeServices,
isBlockStatement,
isCallExpression,
isIdentifier,
isMemberExpression,
isProgram,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+} from '../etc';
+import { ruleCreator } from '../utils';
-const rule = ruleCreator({
+export const noRedundantNotifyRule = ruleCreator({
defaultOptions: [],
meta: {
docs: {
description:
- "Forbids redundant notifications from completed or errored observables.",
- recommended: "error",
+ 'Disallow sending redundant notifications from completed or errored observables.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Redundant notifications are forbidden.",
+ forbidden: 'Redundant notifications are forbidden.',
},
schema: [],
- type: "problem",
+ type: 'problem',
},
- name: "no-redundant-notify",
+ name: 'no-redundant-notify',
create: (context) => {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const { couldBeType } = getTypeServices(context);
return {
- "ExpressionStatement[expression.callee.property.name=/^(complete|error)$/] + ExpressionStatement[expression.callee.property.name=/^(next|complete|error)$/]":
+ 'ExpressionStatement[expression.callee.property.name=/^(complete|error)$/] + ExpressionStatement[expression.callee.property.name=/^(next|complete|error)$/]':
(node: es.ExpressionStatement) => {
- const parent = getParent(node);
+ const parent = node.parent;
if (!parent) {
return;
}
@@ -52,14 +45,14 @@ const rule = ruleCreator({
const index = body.indexOf(node);
const sibling = body[index - 1] as es.ExpressionStatement;
if (
- getExpressionText(sibling, sourceCode) !==
- getExpressionText(node, sourceCode)
+ getExpressionText(sibling, sourceCode)
+ !== getExpressionText(node, sourceCode)
) {
return;
}
if (
- !isExpressionObserver(sibling, couldBeType) ||
- !isExpressionObserver(node, couldBeType)
+ !isExpressionObserver(sibling, couldBeType)
+ || !isExpressionObserver(node, couldBeType)
) {
return;
}
@@ -70,7 +63,7 @@ const rule = ruleCreator({
const { property } = callee;
if (isIdentifier(property)) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: property,
});
}
@@ -83,7 +76,7 @@ const rule = ruleCreator({
function getExpressionText(
expressionStatement: es.ExpressionStatement,
- sourceCode: eslint.SourceCode
+ sourceCode: eslint.SourceCode,
): string | undefined {
if (!isCallExpression(expressionStatement.expression)) {
return undefined;
@@ -102,7 +95,7 @@ function isExpressionObserver(
node: es.Node,
name: string | RegExp,
qualified?: { name: RegExp }
- ) => boolean
+ ) => boolean,
): boolean {
if (!isCallExpression(expressionStatement.expression)) {
return false;
@@ -114,5 +107,3 @@ function isExpressionObserver(
const { object } = callExpression.callee;
return couldBeType(object, /^(Subject|Subscriber)$/);
}
-
-export = rule;
diff --git a/src/rules/no-sharereplay.ts b/src/rules/no-sharereplay.ts
new file mode 100644
index 00000000..bfbe29b7
--- /dev/null
+++ b/src/rules/no-sharereplay.ts
@@ -0,0 +1,53 @@
+import { AST_NODE_TYPES, TSESTree as es } from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
+
+const defaultOptions: readonly {
+ allowConfig?: boolean;
+}[] = [];
+
+export const noSharereplayRule = ruleCreator({
+ defaultOptions,
+ meta: {
+ docs: {
+ description: 'Disallow unsafe `shareReplay` usage.',
+ recommended: 'recommended',
+ },
+ messages: {
+ forbidden: 'shareReplay is forbidden.',
+ forbiddenWithoutConfig:
+ 'shareReplay is forbidden unless a config argument is passed.',
+ },
+ schema: [
+ {
+ properties: {
+ allowConfig: { type: 'boolean', description: 'Allow shareReplay if a config argument is specified.', default: true },
+ },
+ type: 'object',
+ },
+ ],
+ type: 'problem',
+ },
+ name: 'no-sharereplay',
+ create: (context) => {
+ const [config = {}] = context.options;
+ const { allowConfig = true } = config;
+ return {
+ 'CallExpression[callee.name=\'shareReplay\']': (
+ node: es.CallExpression,
+ ) => {
+ let report = true;
+ if (allowConfig) {
+ report
+ = node.arguments.length !== 1
+ || node.arguments[0].type !== AST_NODE_TYPES.ObjectExpression;
+ }
+ if (report) {
+ context.report({
+ messageId: allowConfig ? 'forbiddenWithoutConfig' : 'forbidden',
+ node: node.callee,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-subclass.ts b/src/rules/no-subclass.ts
new file mode 100644
index 00000000..3bdae3db
--- /dev/null
+++ b/src/rules/no-subclass.ts
@@ -0,0 +1,50 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noSubclassRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow subclassing RxJS classes.',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Subclassing RxJS classes is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-subclass',
+ create: (context) => {
+ const { couldBeType } = getTypeServices(context);
+
+ const queryNames = [
+ 'AsyncSubject',
+ 'BehaviorSubject',
+ 'Observable',
+ 'ReplaySubject',
+ 'Scheduler',
+ 'Subject',
+ 'Subscriber',
+ ];
+
+ return {
+ [`ClassDeclaration[superClass.name=/^(${queryNames.join(
+ '|',
+ )})$/] > Identifier.superClass`]: (node: es.Identifier) => {
+ if (
+ queryNames.some((name) =>
+ couldBeType(node, name, { name: /[/\\]rxjs[/\\]/ }),
+ )
+ ) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-subject-unsubscribe.ts b/src/rules/no-subject-unsubscribe.ts
new file mode 100644
index 00000000..40ac8e8e
--- /dev/null
+++ b/src/rules/no-subject-unsubscribe.ts
@@ -0,0 +1,51 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noSubjectUnsubscribeRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow calling the `unsubscribe` method of subjects.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Calling unsubscribe on a subject is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-subject-unsubscribe',
+ create: (context) => {
+ const { couldBeSubject, couldBeSubscription } = getTypeServices(context);
+
+ return {
+ 'MemberExpression[property.name=\'unsubscribe\']': (
+ node: es.MemberExpression,
+ ) => {
+ if (couldBeSubject(node.object)) {
+ context.report({
+ messageId: 'forbidden',
+ node: node.property,
+ });
+ }
+ },
+ 'CallExpression[callee.property.name=\'add\'][arguments.length > 0]': (
+ node: es.CallExpression,
+ ) => {
+ const memberExpression = node.callee as es.MemberExpression;
+ if (couldBeSubscription(memberExpression.object)) {
+ const [arg] = node.arguments;
+ if (couldBeSubject(arg)) {
+ context.report({
+ messageId: 'forbidden',
+ node: arg,
+ });
+ }
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-subject-value.ts b/src/rules/no-subject-value.ts
new file mode 100644
index 00000000..d77c23bf
--- /dev/null
+++ b/src/rules/no-subject-value.ts
@@ -0,0 +1,41 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noSubjectValueRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow accessing the `value` property of a `BehaviorSubject` instance.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden:
+ 'Accessing the value property of a BehaviorSubject is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-subject-value',
+ create: (context) => {
+ const { couldBeBehaviorSubject } = getTypeServices(context);
+
+ return {
+ 'Identifier[name=/^(value|getValue)$/]': (node: es.Identifier) => {
+ const parent = node.parent;
+
+ if (!parent || !('object' in parent)) {
+ return;
+ }
+
+ if (couldBeBehaviorSubject(parent.object)) {
+ context.report({
+ messageId: 'forbidden',
+ node,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-subscribe-handlers.ts b/src/rules/no-subscribe-handlers.ts
new file mode 100644
index 00000000..8a1c9f46
--- /dev/null
+++ b/src/rules/no-subscribe-handlers.ts
@@ -0,0 +1,38 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noSubscribeHandlersRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow passing handlers to `subscribe`.',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Passing handlers to subscribe is forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-subscribe-handlers',
+ create: (context) => {
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+
+ return {
+ 'CallExpression[arguments.length > 0][callee.property.name=\'subscribe\']':
+ (node: es.CallExpression) => {
+ const callee = node.callee as es.MemberExpression;
+ if (
+ couldBeObservable(callee.object)
+ || couldBeType(callee.object, 'Subscribable')
+ ) {
+ context.report({
+ messageId: 'forbidden',
+ node: callee.property,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-subscribe-in-pipe.ts b/src/rules/no-subscribe-in-pipe.ts
new file mode 100644
index 00000000..8f008fb1
--- /dev/null
+++ b/src/rules/no-subscribe-in-pipe.ts
@@ -0,0 +1,63 @@
+import { AST_NODE_TYPES, TSESTree as es } from '@typescript-eslint/utils';
+import { getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noSubscribeInPipeRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description:
+ 'Disallow calling of `subscribe` within any RxJS operator inside a `pipe`.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ fixable: undefined,
+ hasSuggestions: false,
+ messages: {
+ forbidden: 'Subscribe calls within pipe operators are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-subscribe-in-pipe',
+ create: (context) => {
+ const { couldBeObservable, couldBeType } = getTypeServices(context);
+
+ function isWithinPipe(node: es.Node): boolean {
+ let parent = node.parent;
+
+ while (parent) {
+ if (
+ parent.type === AST_NODE_TYPES.CallExpression
+ && parent.callee.type === AST_NODE_TYPES.MemberExpression
+ && parent.callee.property.type === AST_NODE_TYPES.Identifier
+ && parent.callee.property.name === 'pipe'
+ ) {
+ return true;
+ }
+ parent = parent.parent;
+ }
+ return false;
+ }
+
+ return {
+ 'CallExpression > MemberExpression[property.name=\'subscribe\']': (
+ node: es.MemberExpression,
+ ) => {
+ if (
+ !couldBeObservable(node.object)
+ && !couldBeType(node.object, 'Subscribable')
+ ) {
+ return;
+ }
+
+ if (isWithinPipe(node)) {
+ context.report({
+ messageId: 'forbidden',
+ node: node.property,
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/src/rules/no-tap.ts b/src/rules/no-tap.ts
new file mode 100644
index 00000000..65952b58
--- /dev/null
+++ b/src/rules/no-tap.ts
@@ -0,0 +1,37 @@
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { ruleCreator } from '../utils';
+
+export const noTapRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ deprecated: true,
+ docs: {
+ description: 'Disallow the `tap` operator.',
+ },
+ messages: {
+ forbidden: 'The tap operator is forbidden.',
+ },
+ replacedBy: ['ban-operators'],
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-tap',
+ create: (context) => {
+ return {
+ [String.raw`ImportDeclaration[source.value=/^rxjs(\u002foperators)?$/] > ImportSpecifier[imported.name='tap']`]:
+ (node: es.ImportSpecifier) => {
+ const { loc } = node;
+ context.report({
+ messageId: 'forbidden',
+ loc: {
+ ...loc,
+ end: {
+ ...loc.start,
+ column: loc.start.column + 3,
+ },
+ },
+ });
+ },
+ };
+ },
+});
diff --git a/src/rules/no-topromise.ts b/src/rules/no-topromise.ts
new file mode 100644
index 00000000..ee9dde70
--- /dev/null
+++ b/src/rules/no-topromise.ts
@@ -0,0 +1,115 @@
+import { TSESTree as es, TSESLint } from '@typescript-eslint/utils';
+import { getTypeServices, isIdentifier, isImportDeclaration, isImportNamespaceSpecifier, isImportSpecifier } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noTopromiseRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow use of the `toPromise` method.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ hasSuggestions: true,
+ messages: {
+ forbidden: 'The toPromise method is forbidden.',
+ suggestLastValueFrom: 'Use lastValueFrom instead.',
+ suggestFirstValueFrom: 'Use firstValueFrom instead.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-topromise',
+ create: (context) => {
+ const { couldBeObservable } = getTypeServices(context);
+
+ function getQuote(raw: string) {
+ const match = /^\s*('|")/.exec(raw);
+ if (!match) {
+ return undefined;
+ }
+ const [, quote] = match;
+ return quote;
+ }
+
+ function createFix(
+ conversion: 'lastValueFrom' | 'firstValueFrom',
+ callExpression: es.CallExpression,
+ observableNode: es.Node,
+ importDeclarations: es.ImportDeclaration[],
+ ) {
+ return function* fix(fixer: TSESLint.RuleFixer) {
+ let namespace = '';
+ let functionName: string = conversion;
+
+ const rxjsImportDeclaration = importDeclarations.find(node => node.source.value === 'rxjs');
+
+ if (rxjsImportDeclaration?.specifiers?.every(isImportNamespaceSpecifier)) {
+ // Existing rxjs namespace import. Use alias.
+ namespace = rxjsImportDeclaration.specifiers[0].local.name + '.';
+ } else if (rxjsImportDeclaration?.specifiers?.every(isImportSpecifier)) {
+ // Existing rxjs named import.
+ const { specifiers } = rxjsImportDeclaration;
+ const existingSpecifier = specifiers.find(node => (isIdentifier(node.imported) ? node.imported.name : node.imported.value) === functionName);
+ if (existingSpecifier) {
+ // Function already imported. Use its alias, if any.
+ functionName = existingSpecifier.local.name;
+ } else {
+ // Function not already imported. Add it.
+ const lastSpecifier = specifiers[specifiers.length - 1];
+ yield fixer.insertTextAfter(lastSpecifier, `, ${functionName}`);
+ }
+ } else if (importDeclarations.length) {
+ // No rxjs import. Add to end of imports, respecting quotes.
+ const lastImport = importDeclarations[importDeclarations.length - 1];
+ const quote = getQuote(lastImport.source.raw) ?? '"';
+ yield fixer.insertTextAfter(
+ importDeclarations[importDeclarations.length - 1],
+ `\nimport { ${functionName} } from ${quote}rxjs${quote};`,
+ );
+ } else {
+ console.warn('No import declarations found. Unable to suggest a fix.');
+ return;
+ }
+
+ yield fixer.replaceText(
+ callExpression,
+ `${namespace}${functionName}(${context.sourceCode.getText(observableNode)})`,
+ );
+ };
+ }
+
+ return {
+ [`CallExpression[callee.property.name="toPromise"]`]: (
+ node: es.CallExpression,
+ ) => {
+ const memberExpression = node.callee as es.MemberExpression;
+ if (!couldBeObservable(memberExpression.object)) {
+ return;
+ }
+
+ const { body } = context.sourceCode.ast;
+ const importDeclarations = body.filter(isImportDeclaration);
+ if (!importDeclarations.length) {
+ // couldBeObservable yet no imports? Skip.
+ return;
+ }
+
+ context.report({
+ messageId: 'forbidden',
+ node: memberExpression.property,
+ suggest: [
+ {
+ messageId: 'suggestLastValueFrom',
+ fix: createFix('lastValueFrom', node, memberExpression.object, importDeclarations),
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ fix: createFix('firstValueFrom', node, memberExpression.object, importDeclarations),
+ },
+ ],
+ });
+ },
+ };
+ },
+});
diff --git a/src/rules/no-unbound-methods.ts b/src/rules/no-unbound-methods.ts
new file mode 100644
index 00000000..ab7ee39b
--- /dev/null
+++ b/src/rules/no-unbound-methods.ts
@@ -0,0 +1,82 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import {
+ getTypeServices,
+ isCallExpression,
+ isMemberExpression } from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noUnboundMethodsRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow passing unbound methods.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Unbound methods are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-unbound-methods',
+ create: (context) => {
+ const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
+ const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
+ const nodeMap = new WeakMap();
+
+ function mapArguments(node: es.CallExpression | es.NewExpression) {
+ node.arguments.filter(isMemberExpression).forEach((arg) => {
+ const argType = getTypeAtLocation(arg);
+ if (argType.getCallSignatures().length > 0) {
+ nodeMap.set(arg);
+ }
+ });
+ }
+
+ function isObservableOrSubscription(
+ node: es.CallExpression,
+ action: (node: es.CallExpression) => void,
+ ) {
+ if (!isMemberExpression(node.callee)) {
+ return;
+ }
+
+ if (
+ couldBeObservable(node.callee.object)
+ || couldBeSubscription(node.callee.object)
+ ) {
+ action(node);
+ }
+ }
+
+ return {
+ 'CallExpression[callee.property.name=\'pipe\']': (
+ node: es.CallExpression,
+ ) => {
+ isObservableOrSubscription(node, ({ arguments: args }) => {
+ args.filter(isCallExpression).forEach(mapArguments);
+ });
+ },
+ 'CallExpression[callee.property.name=/^(add|subscribe)$/]': (
+ node: es.CallExpression,
+ ) => {
+ isObservableOrSubscription(node, mapArguments);
+ },
+ 'NewExpression[callee.name=\'Subscription\']': mapArguments,
+ 'ThisExpression': (node: es.ThisExpression) => {
+ let parent = node.parent as es.Node | undefined;
+ while (parent) {
+ if (nodeMap.has(parent)) {
+ context.report({
+ messageId: 'forbidden',
+ node: parent,
+ });
+ return;
+ }
+ parent = parent.parent;
+ }
+ },
+ };
+ },
+});
diff --git a/source/rules/no-unsafe-catch.ts b/src/rules/no-unsafe-catch.ts
similarity index 63%
rename from source/rules/no-unsafe-catch.ts
rename to src/rules/no-unsafe-catch.ts
index 8f694ee8..e89b3599 100644
--- a/source/rules/no-unsafe-catch.ts
+++ b/src/rules/no-unsafe-catch.ts
@@ -1,51 +1,43 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import { defaultObservable } from '../constants';
import {
getTypeServices,
isArrowFunctionExpression,
isCallExpression,
isFunctionDeclaration,
- isIdentifier,
-} from "eslint-etc";
-import { defaultObservable } from "../constants";
-import { ruleCreator } from "../utils";
+ isIdentifier } from '../etc';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly {
observable?: string;
}[] = [];
-const rule = ruleCreator({
+export const noUnsafeCatchRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids unsafe `catchError` usage in effects and epics.",
- recommended: false,
+ description: 'Disallow unsafe `catchError` usage in effects and epics.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Unsafe catchError usage in effects and epics are forbidden.",
+ forbidden: 'Unsafe catchError usage in effects and epics are forbidden.',
},
schema: [
{
properties: {
- observable: { type: "string" },
+ observable: { type: 'string', description: 'A RegExp that matches an effect or epic\'s actions observable.', default: defaultObservable },
},
- type: "object",
+ type: 'object',
description: stripIndent`
An optional object with an optional \`observable\` property.
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-unsafe-catch",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-unsafe-catch',
+ create: (context) => {
const invalidOperatorsRegExp = /^(catchError)$/;
const [config = {}] = context.options;
@@ -56,8 +48,8 @@ const rule = ruleCreator({
function isUnsafe([arg]: es.Node[]) {
if (
- arg &&
- (isFunctionDeclaration(arg) || isArrowFunctionExpression(arg))
+ arg
+ && (isFunctionDeclaration(arg) || isArrowFunctionExpression(arg))
) {
// It's only unsafe if it receives a single function argument. If the
// source argument is received, assume that it's used to effect a
@@ -76,11 +68,11 @@ const rule = ruleCreator({
node.arguments.forEach((arg) => {
if (isCallExpression(arg) && isIdentifier(arg.callee)) {
if (
- invalidOperatorsRegExp.test(arg.callee.name) &&
- isUnsafe(arg.arguments)
+ invalidOperatorsRegExp.test(arg.callee.name)
+ && isUnsafe(arg.arguments)
) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: arg.callee,
});
}
@@ -96,5 +88,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/source/rules/no-unsafe-first.ts b/src/rules/no-unsafe-first.ts
similarity index 70%
rename from source/rules/no-unsafe-first.ts
rename to src/rules/no-unsafe-first.ts
index 9fd99126..64ddf1f1 100644
--- a/source/rules/no-unsafe-first.ts
+++ b/src/rules/no-unsafe-first.ts
@@ -1,46 +1,39 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import { getTypeServices, isCallExpression, isIdentifier } from "eslint-etc";
-import { defaultObservable } from "../constants";
-import { ruleCreator } from "../utils";
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import { defaultObservable } from '../constants';
+import { getTypeServices, isCallExpression, isIdentifier } from '../etc';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly {
observable?: string;
}[] = [];
-const rule = ruleCreator({
+export const noUnsafeFirstRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids unsafe `first`/`take` usage in effects and epics.",
- recommended: false,
+ description: 'Disallow unsafe `first`/`take` usage in effects and epics.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
forbidden:
- "Unsafe first and take usage in effects and epics are forbidden.",
+ 'Unsafe first and take usage in effects and epics are forbidden.',
},
schema: [
{
properties: {
- observable: { type: "string" },
+ observable: { type: 'string', description: 'A RegExp that matches an effect or epic\'s actions observable.', default: defaultObservable },
},
- type: "object",
+ type: 'object',
description: stripIndent`
An optional object with an optional \`observable\` property.
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-unsafe-first",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-unsafe-first',
+ create: (context) => {
const invalidOperatorsRegExp = /^(take|first)$/;
const [config = {}] = context.options;
@@ -59,7 +52,7 @@ const rule = ruleCreator({
if (isCallExpression(arg) && isIdentifier(arg.callee)) {
if (invalidOperatorsRegExp.test(arg.callee.name)) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: arg.callee,
});
}
@@ -91,5 +84,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/no-unsafe-subject-next.ts b/src/rules/no-unsafe-subject-next.ts
new file mode 100644
index 00000000..29906cef
--- /dev/null
+++ b/src/rules/no-unsafe-subject-next.ts
@@ -0,0 +1,63 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import * as tsutils from 'ts-api-utils';
+import ts from 'typescript';
+import {
+ couldBeType,
+ isMemberExpression,
+} from '../etc';
+import { ruleCreator } from '../utils';
+
+export const noUnsafeSubjectNext = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow unsafe optional `next` calls.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Unsafe optional next calls are forbidden.',
+ },
+ schema: [],
+ type: 'problem',
+ },
+ name: 'no-unsafe-subject-next',
+ create: (context) => {
+ const { getTypeAtLocation, program } = ESLintUtils.getParserServices(context);
+ const typeChecker = program.getTypeChecker();
+
+ return {
+ [`CallExpression[callee.property.name='next']`]: (
+ node: es.CallExpression,
+ ) => {
+ if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
+ const type = getTypeAtLocation(node.callee.object);
+ if (tsutils.isTypeReference(type) && couldBeType(type, 'Subject')) {
+ const [typeArg] = typeChecker.getTypeArguments(type);
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Any)) {
+ return;
+ }
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Unknown)) {
+ return;
+ }
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Void)) {
+ return;
+ }
+ if (
+ tsutils.isUnionType(typeArg)
+ && typeArg.types.some((t) =>
+ tsutils.isTypeFlagSet(t, ts.TypeFlags.Void),
+ )
+ ) {
+ return;
+ }
+ context.report({
+ messageId: 'forbidden',
+ node: node.callee.property,
+ });
+ }
+ }
+ },
+ };
+ },
+});
diff --git a/source/rules/no-unsafe-switchmap.ts b/src/rules/no-unsafe-switchmap.ts
similarity index 63%
rename from source/rules/no-unsafe-switchmap.ts
rename to src/rules/no-unsafe-switchmap.ts
index bcc28831..71503c2d 100644
--- a/source/rules/no-unsafe-switchmap.ts
+++ b/src/rules/no-unsafe-switchmap.ts
@@ -1,20 +1,13 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import decamelize from "decamelize";
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
+import decamelize from 'decamelize';
+import { defaultObservable } from '../constants';
import {
getTypeServices,
isCallExpression,
isIdentifier,
- isLiteral,
- isMemberExpression,
-} from "eslint-etc";
-import { defaultObservable } from "../constants";
-import { createRegExpForWords, ruleCreator } from "../utils";
+ isLiteral, isMemberExpression } from '../etc';
+import { createRegExpForWords, ruleCreator } from '../utils';
const defaultOptions: readonly {
allow?: string | string[];
@@ -22,41 +15,40 @@ const defaultOptions: readonly {
observable?: string;
}[] = [];
-const rule = ruleCreator({
+export const noUnsafeSwitchmapRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids unsafe `switchMap` usage in effects and epics.",
- recommended: false,
+ description: 'Disallow unsafe `switchMap` usage in effects and epics.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Unsafe switchMap usage in effects and epics is forbidden.",
+ forbidden: 'Unsafe switchMap usage in effects and epics is forbidden.',
},
schema: [
{
properties: {
allow: {
+ description: 'Action types that are allowed to be used with switchMap. Mutually exclusive with `disallow`.',
oneOf: [
- { type: "string" },
- { type: "array", items: { type: "string" } },
+ { type: 'string', description: 'A regular expression string.' },
+ { type: 'array', items: { type: 'string' }, description: 'An array of words.' },
],
},
disallow: {
+ description: 'Action types that are disallowed to be used with switchMap. Mutually exclusive with `allow`.',
oneOf: [
- { type: "string" },
- { type: "array", items: { type: "string" } },
+ { type: 'string', description: 'A regular expression string.' },
+ { type: 'array', items: { type: 'string' }, description: 'An array of words.' },
],
},
observable: {
- oneOf: [
- { type: "string" },
- { type: "array", items: { type: "string" } },
- ],
+ type: 'string',
+ description: 'A RegExp that matches an effect or epic\'s actions observable.',
+ default: defaultObservable,
},
},
- type: "object",
+ type: 'object',
description: stripIndent`
An optional object with optional \`allow\`, \`disallow\` and \`observable\` properties.
The properties can be specified as regular expression strings or as arrays of words.
@@ -66,19 +58,19 @@ const rule = ruleCreator({
`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-unsafe-switchmap",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-unsafe-switchmap',
+ create: (context) => {
const defaultDisallow = [
- "add",
- "create",
- "delete",
- "post",
- "put",
- "remove",
- "set",
- "update",
+ 'add',
+ 'create',
+ 'delete',
+ 'post',
+ 'put',
+ 'remove',
+ 'set',
+ 'update',
];
let allowRegExp: RegExp | undefined;
@@ -101,7 +93,7 @@ const rule = ruleCreator({
function shouldDisallow(args: es.Node[]): boolean {
const names = args
.map((arg) => {
- if (isLiteral(arg) && typeof arg.value === "string") {
+ if (isLiteral(arg) && typeof arg.value === 'string') {
return arg.value;
}
if (isIdentifier(arg)) {
@@ -111,7 +103,7 @@ const rule = ruleCreator({
return arg.property.name;
}
- return "";
+ return '';
})
.map((name) => decamelize(name));
@@ -132,9 +124,9 @@ const rule = ruleCreator({
const hasUnsafeOfType = node.arguments.some((arg) => {
if (
- isCallExpression(arg) &&
- isIdentifier(arg.callee) &&
- arg.callee.name === "ofType"
+ isCallExpression(arg)
+ && isIdentifier(arg.callee)
+ && arg.callee.name === 'ofType'
) {
return shouldDisallow(arg.arguments);
}
@@ -146,12 +138,12 @@ const rule = ruleCreator({
node.arguments.forEach((arg) => {
if (
- isCallExpression(arg) &&
- isIdentifier(arg.callee) &&
- arg.callee.name === "switchMap"
+ isCallExpression(arg)
+ && isIdentifier(arg.callee)
+ && arg.callee.name === 'switchMap'
) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: arg.callee,
});
}
@@ -166,5 +158,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/source/rules/no-unsafe-takeuntil.ts b/src/rules/no-unsafe-takeuntil.ts
similarity index 50%
rename from source/rules/no-unsafe-takeuntil.ts
rename to src/rules/no-unsafe-takeuntil.ts
index b30aeb49..5ff9b984 100644
--- a/source/rules/no-unsafe-takeuntil.ts
+++ b/src/rules/no-unsafe-takeuntil.ts
@@ -1,135 +1,129 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
+import { TSESTree as es } from '@typescript-eslint/utils';
+import { stripIndent } from 'common-tags';
import {
- getParent,
getTypeServices,
isCallExpression,
isIdentifier,
isMemberExpression,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+} from '../etc';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly {
alias?: string[];
allow?: string[];
}[] = [];
-const rule = ruleCreator({
+const allowedOperators = [
+ 'count',
+ 'defaultIfEmpty',
+ 'endWith',
+ 'every',
+ 'finalize',
+ 'finally',
+ 'isEmpty',
+ 'last',
+ 'max',
+ 'min',
+ 'publish',
+ 'publishBehavior',
+ 'publishLast',
+ 'publishReplay',
+ 'reduce',
+ 'share',
+ 'shareReplay',
+ 'skipLast',
+ 'takeLast',
+ 'throwIfEmpty',
+ 'toArray',
+];
+
+export const noUnsafeTakeuntilRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Forbids the application of operators after `takeUntil`.",
- recommended: "error",
+ description: 'Disallow applying operators after `takeUntil`.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
- forbidden: "Applying operators after takeUntil is forbidden.",
+ forbidden: 'Applying operators after takeUntil is forbidden.',
},
schema: [
{
properties: {
- alias: { type: "array", items: { type: "string" } },
- allow: { type: "array", items: { type: "string" } },
+ alias: { type: 'array', items: { type: 'string' }, description: 'An array of operator names that should be treated similarly to `takeUntil`.' },
+ allow: { type: 'array', items: { type: 'string' }, description: 'An array of operator names that are allowed to follow `takeUntil`.', default: allowedOperators },
},
- type: "object",
+ type: 'object',
description: stripIndent`
An optional object with optional \`alias\` and \`allow\` properties.
The \`alias\` property is an array containing the names of operators that aliases for \`takeUntil\`.
The \`allow\` property is an array containing the names of the operators that are allowed to follow \`takeUntil\`.`,
},
],
- type: "problem",
+ type: 'problem',
},
- name: "no-unsafe-takeuntil",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'no-unsafe-takeuntil',
+ create: (context) => {
let checkedOperatorsRegExp = /^takeUntil$/;
- const allowedOperators = [
- "count",
- "defaultIfEmpty",
- "endWith",
- "every",
- "finalize",
- "finally",
- "isEmpty",
- "last",
- "max",
- "min",
- "publish",
- "publishBehavior",
- "publishLast",
- "publishReplay",
- "reduce",
- "share",
- "shareReplay",
- "skipLast",
- "takeLast",
- "throwIfEmpty",
- "toArray",
- ];
const [config = {}] = context.options;
const { alias, allow = allowedOperators } = config;
if (alias) {
checkedOperatorsRegExp = new RegExp(
- `^(${alias.concat("takeUntil").join("|")})$`
+ `^(${alias.concat('takeUntil').join('|')})$`,
);
}
const { couldBeObservable } = getTypeServices(context);
function checkNode(node: es.CallExpression) {
- const pipeCallExpression = getParent(node) as es.CallExpression;
+ const pipeCallExpression = node.parent as es.CallExpression;
if (
- !pipeCallExpression.arguments ||
- !couldBeObservable(pipeCallExpression)
+ !pipeCallExpression.arguments
+ || !couldBeObservable(pipeCallExpression)
) {
return;
}
- type State = "allowed" | "disallowed" | "taken";
+ type State = 'allowed' | 'disallowed' | 'taken';
pipeCallExpression.arguments.reduceRight((state, arg) => {
- if (state === "taken") {
+ if (state === 'taken') {
return state;
}
if (!isCallExpression(arg)) {
- return "disallowed";
+ return 'disallowed';
}
let operatorName: string;
if (isIdentifier(arg.callee)) {
operatorName = arg.callee.name;
} else if (
- isMemberExpression(arg.callee) &&
- isIdentifier(arg.callee.property)
+ isMemberExpression(arg.callee)
+ && isIdentifier(arg.callee.property)
) {
operatorName = arg.callee.property.name;
} else {
- return "disallowed";
+ return 'disallowed';
}
if (checkedOperatorsRegExp.test(operatorName)) {
- if (state === "disallowed") {
+ if (state === 'disallowed') {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: arg.callee,
});
}
- return "taken";
+ return 'taken';
}
if (!allow.includes(operatorName)) {
- return "disallowed";
+ return 'disallowed';
}
return state;
- }, "allowed" as State);
+ }, 'allowed' as State);
}
return {
@@ -140,5 +134,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/source/rules/prefer-observer.ts b/src/rules/prefer-observer.ts
similarity index 53%
rename from source/rules/prefer-observer.ts
rename to src/rules/prefer-observer.ts
index dfef95ee..0c29c5c4 100644
--- a/source/rules/prefer-observer.ts
+++ b/src/rules/prefer-observer.ts
@@ -1,50 +1,46 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
import {
TSESTree as es,
TSESLint as eslint,
-} from "@typescript-eslint/experimental-utils";
+} from '@typescript-eslint/utils';
import {
getTypeServices,
isArrowFunctionExpression,
isFunctionExpression,
isMemberExpression,
-} from "eslint-etc";
-import { ruleCreator } from "../utils";
+} from '../etc';
+import { ruleCreator } from '../utils';
const defaultOptions: readonly {
allowNext?: boolean;
}[] = [];
-const rule = ruleCreator({
+export const preferObserverRule = ruleCreator({
defaultOptions,
meta: {
docs: {
description:
- "Forbids the passing separate handlers to `subscribe` and `tap`.",
- recommended: false,
+ 'Disallow passing separate handlers to `subscribe` and `tap`.',
+ recommended: 'recommended',
+ requiresTypeChecking: true,
},
- fixable: "code",
+ fixable: 'code',
hasSuggestions: true,
messages: {
forbidden:
- "Passing separate handlers is forbidden; pass an observer instead.",
+ 'Passing separate handlers is forbidden; pass an observer instead.',
},
schema: [
{
properties: {
- allowNext: { type: "boolean" },
+ allowNext: { type: 'boolean', description: 'Allows a single `next` callback.', default: true },
},
- type: "object",
+ type: 'object',
},
],
- type: "problem",
+ type: 'problem',
},
- name: "prefer-observer",
- create: (context, unused: typeof defaultOptions) => {
+ name: 'prefer-observer',
+ create: (context) => {
const { couldBeFunction, couldBeObservable } = getTypeServices(context);
const [config = {}] = context.options;
const { allowNext = true } = config;
@@ -56,59 +52,59 @@ const rule = ruleCreator({
}
function* fix(fixer: eslint.RuleFixer) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const [nextArg, errorArg, completeArg] = args;
- const nextArgText = nextArg ? sourceCode.getText(nextArg) : "";
- const errorArgText = errorArg ? sourceCode.getText(errorArg) : "";
+ const nextArgText = nextArg ? sourceCode.getText(nextArg) : '';
+ const errorArgText = errorArg ? sourceCode.getText(errorArg) : '';
const completeArgText = completeArg
? sourceCode.getText(completeArg)
- : "";
- let observer = "{";
+ : '';
+ let observer = '{';
if (
- nextArgText &&
- nextArgText !== "undefined" &&
- nextArgText !== "null"
+ nextArgText
+ && nextArgText !== 'undefined'
+ && nextArgText !== 'null'
) {
observer += ` next: ${nextArgText}${
isValidArgText(errorArgText) || isValidArgText(completeArgText)
- ? ","
- : ""
+ ? ','
+ : ''
}`;
}
if (
- errorArgText &&
- errorArgText !== "undefined" &&
- errorArgText !== "null"
+ errorArgText
+ && errorArgText !== 'undefined'
+ && errorArgText !== 'null'
) {
observer += ` error: ${errorArgText}${
- isValidArgText(completeArgText) ? "," : ""
+ isValidArgText(completeArgText) ? ',' : ''
}`;
}
if (
- completeArgText &&
- completeArgText !== "undefined" &&
- completeArgText !== "null"
+ completeArgText
+ && completeArgText !== 'undefined'
+ && completeArgText !== 'null'
) {
observer += ` complete: ${completeArgText}`;
}
- observer += " }";
+ observer += ' }';
yield fixer.replaceText(callExpression.arguments[0], observer);
const [, start] = callExpression.arguments[0].range;
- const [, end] =
- callExpression.arguments[callExpression.arguments.length - 1].range;
+ const [, end]
+ = callExpression.arguments[callExpression.arguments.length - 1].range;
yield fixer.removeRange([start, end]);
}
if (args.length > 1) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: reportNode,
fix,
suggest: [
{
- messageId: "forbidden",
+ messageId: 'forbidden',
fix,
},
],
@@ -116,17 +112,17 @@ const rule = ruleCreator({
} else if (args.length === 1 && !allowNext) {
const [arg] = args;
if (
- isArrowFunctionExpression(arg) ||
- isFunctionExpression(arg) ||
- couldBeFunction(arg)
+ isArrowFunctionExpression(arg)
+ || isFunctionExpression(arg)
+ || couldBeFunction(arg)
) {
context.report({
- messageId: "forbidden",
+ messageId: 'forbidden',
node: reportNode,
fix,
suggest: [
{
- messageId: "forbidden",
+ messageId: 'forbidden',
fix,
},
],
@@ -136,17 +132,15 @@ const rule = ruleCreator({
}
return {
- "CallExpression[callee.property.name='pipe'] > CallExpression[callee.name='tap']":
- (node: es.CallExpression) => checkArgs(node, node.callee),
- "CallExpression[callee.property.name='subscribe']": (
- node: es.CallExpression
- ) => checkArgs(node, (node.callee as es.MemberExpression).property),
+ 'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.name=\'tap\']':
+ (node: es.CallExpression) => { checkArgs(node, node.callee); },
+ 'CallExpression[callee.property.name=\'subscribe\']': (
+ node: es.CallExpression,
+ ) => { checkArgs(node, (node.callee as es.MemberExpression).property); },
};
},
});
-export = rule;
-
function isValidArgText(argText: string) {
- return argText && argText !== "undefined" && argText !== "null";
+ return argText && argText !== 'undefined' && argText !== 'null';
}
diff --git a/src/rules/prefer-root-operators.ts b/src/rules/prefer-root-operators.ts
new file mode 100644
index 00000000..60c69ecf
--- /dev/null
+++ b/src/rules/prefer-root-operators.ts
@@ -0,0 +1,168 @@
+import { TSESTree as es, TSESLint } from '@typescript-eslint/utils';
+import { isIdentifier, isImportSpecifier, isLiteral } from '../etc';
+import { ruleCreator } from '../utils';
+
+// See https://rxjs.dev/guide/importing#how-to-migrate
+
+const RENAMED_OPERATORS: Record = {
+ combineLatest: 'combineLatestWith',
+ concat: 'concatWith',
+ merge: 'mergeWith',
+ onErrorResumeNext: 'onErrorResumeNextWith',
+ race: 'raceWith',
+ zip: 'zipWith',
+};
+
+const DEPRECATED_OPERATORS = [
+ 'partition',
+];
+
+export const preferRootOperatorsRule = ruleCreator({
+ defaultOptions: [],
+ meta: {
+ docs: {
+ description: 'Disallow importing operators from `rxjs/operators`.',
+ recommended: 'recommended',
+ },
+ fixable: 'code',
+ hasSuggestions: true,
+ messages: {
+ forbidden: 'RxJS imports from `rxjs/operators` are forbidden; import from `rxjs` instead.',
+ forbiddenWithoutFix: 'RxJS imports from `rxjs/operators` are forbidden; import from `rxjs` instead. Note some operators may have been renamed or deprecated.',
+ suggest: 'Replace with import from `rxjs`.',
+ },
+ schema: [],
+ type: 'suggestion',
+ },
+ name: 'prefer-root-operators',
+ create: (context) => {
+ function getQuote(raw: string): string | undefined {
+ const match = /^\s*('|")/.exec(raw);
+ if (!match) {
+ return undefined;
+ }
+ const [, quote] = match;
+ return quote;
+ }
+
+ function getSourceReplacement(rawLocation: string): string | undefined {
+ const quote = getQuote(rawLocation);
+ if (!quote) {
+ return undefined;
+ }
+ if (/^['"]rxjs\/operators/.test(rawLocation)) {
+ return `${quote}rxjs${quote}`;
+ }
+ return undefined;
+ }
+
+ function hasDeprecatedOperators(specifiers?: es.ImportSpecifier[] | es.ExportSpecifier[]): boolean {
+ return !!specifiers?.some(s => DEPRECATED_OPERATORS.includes(getName(getOperatorNode(s))));
+ }
+
+ function getName(node: es.Identifier | es.StringLiteral): string {
+ return isIdentifier(node) ? node.name : node.value;
+ }
+
+ function getOperatorNode(node: es.ImportSpecifier | es.ExportSpecifier): es.Identifier | es.StringLiteral {
+ return isImportSpecifier(node) ? node.imported : node.local;
+ }
+
+ function getAliasNode(node: es.ImportSpecifier | es.ExportSpecifier): es.Identifier | es.StringLiteral {
+ return isImportSpecifier(node) ? node.local : node.exported;
+ }
+
+ function getOperatorReplacement(name: string): string | undefined {
+ return RENAMED_OPERATORS[name];
+ }
+
+ function isNodesEqual(a: es.Node, b: es.Node): boolean {
+ return a.range[0] === b.range[0] && a.range[1] === b.range[1];
+ }
+
+ function createFix(source: es.Node, replacement: string, specifiers: es.ImportSpecifier[] | es.ExportSpecifier[]) {
+ return function* fix(fixer: TSESLint.RuleFixer) {
+ // Rename the module name.
+ yield fixer.replaceText(source, replacement);
+
+ // Rename the imported operators if necessary.
+ for (const specifier of specifiers) {
+ const operatorNode = getOperatorNode(specifier);
+ const operatorName = getName(operatorNode);
+
+ const operatorReplacement = getOperatorReplacement(operatorName);
+ if (!operatorReplacement) {
+ // The operator has the same name.
+ continue;
+ }
+
+ const aliasNode = getAliasNode(specifier);
+ if (isNodesEqual(aliasNode, operatorNode)) {
+ // concat -> concatWith as concat
+ yield fixer.insertTextBefore(operatorNode, operatorReplacement + ' as ');
+ } else if (isIdentifier(operatorNode)) {
+ // concat as c -> concatWith as c
+ yield fixer.replaceText(operatorNode, operatorReplacement);
+ } else {
+ // 'concat' as c -> 'concatWith' as c
+ const quote = getQuote(operatorNode.raw);
+ if (!quote) {
+ continue;
+ }
+ yield fixer.replaceText(operatorNode, quote + operatorReplacement + quote);
+ }
+ }
+ };
+ }
+
+ function reportNode(source: es.Literal, specifiers?: es.ImportSpecifier[] | es.ExportSpecifier[]): void {
+ const replacement = getSourceReplacement(source.raw);
+ if (!replacement || hasDeprecatedOperators(specifiers)) {
+ context.report({
+ messageId: 'forbiddenWithoutFix',
+ node: source,
+ });
+ return;
+ }
+
+ if (!specifiers) {
+ context.report({
+ messageId: 'forbiddenWithoutFix',
+ node: source,
+ suggest: [{ messageId: 'suggest', fix: (fixer) => fixer.replaceText(source, replacement) }],
+ });
+ return;
+ }
+
+ const fix = createFix(source, replacement, specifiers);
+ context.report({
+ fix,
+ messageId: 'forbidden',
+ node: source,
+ suggest: [{ messageId: 'suggest', fix }],
+ });
+ }
+
+ return {
+ 'ImportDeclaration[source.value="rxjs/operators"]': (node: es.ImportDeclaration) => {
+ // Exclude side effect imports, default imports, and namespace imports.
+ const specifiers = node.specifiers.length && node.specifiers.every(importClause => isImportSpecifier(importClause))
+ ? node.specifiers
+ : undefined;
+
+ reportNode(node.source, specifiers);
+ },
+ 'ImportExpression[source.value="rxjs/operators"]': (node: es.ImportExpression) => {
+ if (isLiteral(node.source)) {
+ reportNode(node.source);
+ }
+ },
+ 'ExportNamedDeclaration[source.value="rxjs/operators"]': (node: es.ExportNamedDeclarationWithSource) => {
+ reportNode(node.source, node.specifiers);
+ },
+ 'ExportAllDeclaration[source.value="rxjs/operators"]': (node: es.ExportAllDeclaration) => {
+ reportNode(node.source);
+ },
+ };
+ },
+});
diff --git a/source/rules/suffix-subjects.ts b/src/rules/suffix-subjects.ts
similarity index 52%
rename from source/rules/suffix-subjects.ts
rename to src/rules/suffix-subjects.ts
index 4c774bd9..9ab67b8b 100644
--- a/source/rules/suffix-subjects.ts
+++ b/src/rules/suffix-subjects.ts
@@ -1,17 +1,10 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESTree as es } from "@typescript-eslint/experimental-utils";
+import { AST_NODE_TYPES, TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
import {
findParent,
getLoc,
- getParent,
- getParserServices,
getTypeServices,
-} from "eslint-etc";
-import { escapeRegExp, ruleCreator } from "../utils";
+} from '../etc';
+import { escapeRegExp, ruleCreator } from '../utils';
const defaultOptions: readonly {
parameters?: boolean;
@@ -21,35 +14,33 @@ const defaultOptions: readonly {
variables?: boolean;
}[] = [];
-const rule = ruleCreator({
+export const suffixSubjectsRule = ruleCreator({
defaultOptions,
meta: {
docs: {
- description: "Enforces the use of a suffix in subject identifiers.",
- recommended: false,
+ description: 'Enforce the use of a suffix in subject identifiers.',
+ requiresTypeChecking: true,
},
- fixable: undefined,
- hasSuggestions: false,
messages: {
forbidden: `Subject identifiers must end with "{{suffix}}".`,
},
schema: [
{
properties: {
- parameters: { type: "boolean" },
- properties: { type: "boolean" },
- suffix: { type: "string" },
- types: { type: "object" },
- variables: { type: "boolean" },
+ parameters: { type: 'boolean', description: 'Require for parameters.' },
+ properties: { type: 'boolean', description: 'Require for properties.' },
+ suffix: { type: 'string', description: 'The suffix to enforce.' },
+ types: { type: 'object', description: 'Enforce for specific types. Keys are a RegExp, values are a boolean.' },
+ variables: { type: 'boolean', description: 'Require for variables.' },
},
- type: "object",
+ type: 'object',
},
],
- type: "problem",
+ type: 'problem',
},
- name: "suffix-subjects",
- create: (context, unused: typeof defaultOptions) => {
- const { esTreeNodeToTSNodeMap } = getParserServices(context);
+ name: 'suffix-subjects',
+ create: (context) => {
+ const { esTreeNodeToTSNodeMap } = ESLintUtils.getParserServices(context);
const { couldBeType } = getTypeServices(context);
const [config = {}] = context.options;
@@ -65,7 +56,7 @@ const rule = ruleCreator({
Object.entries(config.types).forEach(
([key, validate]: [string, boolean]) => {
types.push({ regExp: new RegExp(key), validate });
- }
+ },
);
} else {
types.push({
@@ -74,46 +65,46 @@ const rule = ruleCreator({
});
}
- const { suffix = "Subject" } = config;
+ const { suffix = 'Subject' } = config;
const suffixRegex = new RegExp(
String.raw`${escapeRegExp(suffix)}\$?$`,
- "i"
+ 'i',
);
function checkNode(nameNode: es.Node, typeNode?: es.Node) {
- let tsNode = esTreeNodeToTSNodeMap.get(nameNode);
+ const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
const text = tsNode.getText();
if (
- !suffixRegex.test(text) &&
- couldBeType(typeNode || nameNode, "Subject")
+ !suffixRegex.test(text)
+ && couldBeType(typeNode ?? nameNode, 'Subject')
) {
for (const type of types) {
const { regExp, validate } = type;
- if (couldBeType(typeNode || nameNode, regExp) && !validate) {
+ if (couldBeType(typeNode ?? nameNode, regExp) && !validate) {
return;
}
}
context.report({
data: { suffix },
loc: getLoc(tsNode),
- messageId: "forbidden",
+ messageId: 'forbidden',
});
}
}
return {
- "ArrayPattern > Identifier": (node: es.Identifier) => {
+ 'ArrayPattern > Identifier': (node: es.Identifier) => {
const found = findParent(
node,
- "ArrowFunctionExpression",
- "FunctionDeclaration",
- "FunctionExpression",
- "VariableDeclarator"
+ 'ArrowFunctionExpression',
+ 'FunctionDeclaration',
+ 'FunctionExpression',
+ 'VariableDeclarator',
);
if (!found) {
return;
}
- if (!validate.variables && found.type === "VariableDeclarator") {
+ if (!validate.variables && found.type === AST_NODE_TYPES.VariableDeclarator) {
return;
}
if (!validate.parameters) {
@@ -121,110 +112,109 @@ const rule = ruleCreator({
}
checkNode(node);
},
- "ArrowFunctionExpression > Identifier": (node: es.Identifier) => {
+ 'ArrowFunctionExpression > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
- const parent = getParent(node) as es.ArrowFunctionExpression;
+ const parent = node.parent as es.ArrowFunctionExpression;
if (node !== parent.body) {
checkNode(node);
}
}
},
- "PropertyDefinition[computed=false]": (node: es.PropertyDefinition) => {
- const anyNode = node as any;
+ 'PropertyDefinition[computed=false]': (node: es.PropertyDefinition) => {
+ const anyNode = node;
if (validate.properties) {
checkNode(anyNode.key);
}
},
- "FunctionDeclaration > Identifier": (node: es.Identifier) => {
+ 'FunctionDeclaration > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
- const parent = getParent(node) as es.FunctionDeclaration;
+ const parent = node.parent as es.FunctionDeclaration;
if (node !== parent.id) {
checkNode(node);
}
}
},
- "FunctionExpression > Identifier": (node: es.Identifier) => {
+ 'FunctionExpression > Identifier': (node: es.Identifier) => {
if (validate.parameters) {
- const parent = getParent(node) as es.FunctionExpression;
+ const parent = node.parent as es.FunctionExpression;
if (node !== parent.id) {
checkNode(node);
}
}
},
- "MethodDefinition[kind='get'][computed=false]": (
- node: es.MethodDefinition
+ 'MethodDefinition[kind=\'get\'][computed=false]': (
+ node: es.MethodDefinition,
) => {
if (validate.properties) {
checkNode(node.key, node);
}
},
- "MethodDefinition[kind='set'][computed=false]": (
- node: es.MethodDefinition
+ 'MethodDefinition[kind=\'set\'][computed=false]': (
+ node: es.MethodDefinition,
) => {
if (validate.properties) {
checkNode(node.key, node);
}
},
- "ObjectExpression > Property[computed=false] > Identifier": (
- node: es.ObjectExpression
+ 'ObjectExpression > Property[computed=false] > Identifier': (
+ node: es.ObjectExpression,
) => {
if (validate.properties) {
- const parent = getParent(node) as es.Property;
+ const parent = node.parent as es.Property;
if (node === parent.key) {
checkNode(node);
}
}
},
- "ObjectPattern > Property > Identifier": (node: es.Identifier) => {
+ 'ObjectPattern > Property > Identifier': (node: es.Identifier) => {
const found = findParent(
node,
- "ArrowFunctionExpression",
- "FunctionDeclaration",
- "FunctionExpression",
- "VariableDeclarator"
+ 'ArrowFunctionExpression',
+ 'FunctionDeclaration',
+ 'FunctionExpression',
+ 'VariableDeclarator',
);
if (!found) {
return;
}
- if (!validate.variables && found.type === "VariableDeclarator") {
+ if (!validate.variables && found.type === AST_NODE_TYPES.VariableDeclarator) {
return;
}
if (!validate.parameters) {
return;
}
- const parent = getParent(node) as es.Property;
+ const parent = node.parent as es.Property;
if (node === parent.value) {
checkNode(node);
}
},
- "TSCallSignatureDeclaration > Identifier": (node: es.Node) => {
+ 'TSCallSignatureDeclaration > Identifier': (node: es.Node) => {
if (validate.parameters) {
checkNode(node);
}
},
- "TSConstructSignatureDeclaration > Identifier": (node: es.Node) => {
+ 'TSConstructSignatureDeclaration > Identifier': (node: es.Node) => {
if (validate.parameters) {
checkNode(node);
}
},
- "TSMethodSignature > Identifier": (node: es.Node) => {
+ 'TSMethodSignature > Identifier': (node: es.Node) => {
if (validate.parameters) {
checkNode(node);
}
},
- "TSParameterProperty > Identifier": (node: es.Identifier) => {
+ 'TSParameterProperty > Identifier': (node: es.Identifier) => {
if (validate.parameters || validate.properties) {
checkNode(node);
}
},
- "TSPropertySignature[computed=false]": (node: es.Node) => {
- const anyNode = node as any;
+ 'TSPropertySignature[computed=false]': (node: es.TSPropertySignature) => {
if (validate.properties) {
- checkNode(anyNode.key);
+ checkNode(node.key);
}
},
- "VariableDeclarator > Identifier": (node: es.Identifier) => {
- const parent = getParent(node) as es.VariableDeclarator;
+ 'VariableDeclarator > Identifier': (node: es.Identifier) => {
+ const parent = node.parent as es.VariableDeclarator;
if (validate.variables && node === parent.id) {
checkNode(node);
}
@@ -232,5 +222,3 @@ const rule = ruleCreator({
};
},
});
-
-export = rule;
diff --git a/src/rules/throw-error.ts b/src/rules/throw-error.ts
new file mode 100644
index 00000000..e63e027c
--- /dev/null
+++ b/src/rules/throw-error.ts
@@ -0,0 +1,94 @@
+import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
+import * as tsutils from 'ts-api-utils';
+import ts from 'typescript';
+import { couldBeFunction, couldBeType, getTypeServices } from '../etc';
+import { ruleCreator } from '../utils';
+
+const defaultOptions: readonly {
+ allowThrowingAny?: boolean;
+ allowThrowingUnknown?: boolean;
+}[] = [];
+
+export const throwErrorRule = ruleCreator({
+ defaultOptions,
+ meta: {
+ docs: {
+ description:
+ 'Enforce passing only `Error` values to `throwError`.',
+ recommended: {
+ recommended: true,
+ strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }],
+ },
+ requiresTypeChecking: true,
+ },
+ messages: {
+ forbidden: 'Passing non-Error values is forbidden.',
+ },
+ schema: [
+ {
+ properties: {
+ allowThrowingAny: { type: 'boolean', default: true, description: 'Whether to always allow throwing values typed as `any`.' },
+ allowThrowingUnknown: { type: 'boolean', default: true, description: 'Whether to always allow throwing values typed as `unknown`.' },
+ },
+ type: 'object',
+ },
+ ],
+ type: 'problem',
+ },
+ name: 'throw-error',
+ create: (context) => {
+ const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = ESLintUtils.getParserServices(context);
+ const { couldBeObservable } = getTypeServices(context);
+ const [config = {}] = context.options;
+ const { allowThrowingAny = true, allowThrowingUnknown = true } = config;
+
+ function checkThrowArgument(node: es.Node) {
+ let type = getTypeAtLocation(node);
+ let reportNode = node;
+
+ if (couldBeFunction(type)) {
+ reportNode = (node as es.ArrowFunctionExpression).body ?? node;
+
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ const annotation = (tsNode as ts.ArrowFunction).type;
+ const body = (tsNode as ts.ArrowFunction).body;
+ type = program.getTypeChecker().getTypeAtLocation(annotation ?? body);
+ }
+
+ if (allowThrowingAny && tsutils.isIntrinsicAnyType(type)) {
+ return;
+ }
+
+ if (allowThrowingUnknown && tsutils.isIntrinsicUnknownType(type)) {
+ return;
+ }
+
+ if (couldBeType(type, /^Error$/)) {
+ return;
+ }
+
+ context.report({
+ messageId: 'forbidden',
+ node: reportNode,
+ });
+ }
+
+ function checkNode(node: es.CallExpression) {
+ if (couldBeObservable(node)) {
+ const [arg] = node.arguments;
+ if (arg) {
+ checkThrowArgument(arg);
+ }
+ }
+ }
+
+ return {
+ 'CallExpression[callee.name=\'throwError\']': (node: es.CallExpression) => {
+ checkNode(node);
+ },
+ 'CallExpression[callee.property.name=\'throwError\']': (node: es.CallExpression) => {
+ checkNode(node);
+ },
+ };
+ },
+});
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 00000000..7035d045
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,32 @@
+import { ESLintUtils, TSESLint } from '@typescript-eslint/utils';
+
+export function createRegExpForWords(
+ config: string | string[],
+): RegExp | undefined {
+ if (!config?.length) {
+ return undefined;
+ }
+ const flags = 'i';
+ if (typeof config === 'string') {
+ return new RegExp(config, flags);
+ }
+ const words = config;
+ const joined = words.map((word) => String.raw`(\b|_)${word}(\b|_)`).join('|');
+ return new RegExp(`(${joined})`, flags);
+}
+
+export function escapeRegExp(text: string): string {
+ // https://stackoverflow.com/a/3561711/6680611
+ return text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
+
+export interface RxjsXRuleDocs {
+ description: string;
+ recommended?: TSESLint.RuleRecommendation | TSESLint.RuleRecommendationAcrossConfigs;
+ requiresTypeChecking?: boolean;
+}
+
+export const ruleCreator = ESLintUtils.RuleCreator(
+ (name) =>
+ `https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/blob/main/docs/rules/${name}.md`,
+);
diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json
deleted file mode 100644
index e5cf7200..00000000
--- a/tests/.eslintrc.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "parserOptions": {
- "project": "tsconfig.json"
- }
-}
diff --git a/tests/configs/recommended.test.ts b/tests/configs/recommended.test.ts
new file mode 100644
index 00000000..27e2fa5c
--- /dev/null
+++ b/tests/configs/recommended.test.ts
@@ -0,0 +1,21 @@
+import { createRecommendedConfig } from '../../src/configs/recommended';
+
+describe('recommended', () => {
+ const mockPlugin = {};
+ const config = createRecommendedConfig(mockPlugin);
+
+ it('should add the rxjs-x plugin', () => {
+ expect(config.plugins).toEqual({ 'rxjs-x': mockPlugin });
+ });
+
+ it('should use the defaults of each rule', () => {
+ expect(config.rules).instanceOf(Object);
+ for (const ruleEntry of Object.values(config.rules)) {
+ expect(ruleEntry).toEqual('error');
+ }
+ });
+
+ it('should be named', () => {
+ expect(config.name).toEqual('rxjs-x/recommended');
+ });
+});
diff --git a/tests/configs/strict.test.ts b/tests/configs/strict.test.ts
new file mode 100644
index 00000000..0e393d20
--- /dev/null
+++ b/tests/configs/strict.test.ts
@@ -0,0 +1,23 @@
+import { createRecommendedConfig } from '../../src/configs/recommended';
+import { createStrictConfig } from '../../src/configs/strict';
+
+describe('strict', () => {
+ const mockPlugin = {};
+ const config = createStrictConfig(mockPlugin);
+
+ it('should add the rxjs-x plugin', () => {
+ expect(config.plugins).toEqual({ 'rxjs-x': mockPlugin });
+ });
+
+ it('should include the recommended rules', () => {
+ const recommendedConfig = createRecommendedConfig(mockPlugin);
+
+ for (const rule of Object.keys(recommendedConfig.rules)) {
+ expect(config.rules).toHaveProperty(rule);
+ }
+ });
+
+ it('should be named', () => {
+ expect(config.name).toEqual('rxjs-x/strict');
+ });
+});
diff --git a/tests/etc/could-be-type.test.ts b/tests/etc/could-be-type.test.ts
new file mode 100644
index 00000000..55f9a544
--- /dev/null
+++ b/tests/etc/could-be-type.test.ts
@@ -0,0 +1,136 @@
+import ts from 'typescript';
+import { couldBeType } from '../../src/etc/could-be-type';
+import { createSourceFileAndTypeChecker } from './create-source-file-and-type-checker';
+
+describe('couldBeType', () => {
+ it('should match a specific type', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ class A {}
+ let a: A;
+ `,
+ );
+ const node = (sourceFile.statements[1] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ });
+
+ it('should not match different types', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ class A {}
+ class B {}
+ let b: B;
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(false);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should match a base type', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ class A {}
+ class B extends A {}
+ let b: B;
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should match an implemented interface', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ interface A { name: string; }
+ class B implements A { name = ""; }
+ let b: B;
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should match an implemented generic interface', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ interface A { value: T; }
+ class B implements A { constructor(public value: T) {} }
+ let b = new B("B");
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should match an intersection type', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ class A {}
+ class B {}
+ let ab: A & B;
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should match a union type', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ class A {}
+ class B {}
+ let ab: A | B;
+ `,
+ );
+ const node = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const type = typeChecker.getTypeAtLocation(node);
+
+ expect(couldBeType(type, 'A')).toBe(true);
+ expect(couldBeType(type, 'B')).toBe(true);
+ });
+
+ it('should support fully-qualified types', () => {
+ const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(
+ `
+ import { A } from "/a";
+ class B {}
+ let a: A;
+ let b: B;
+ `,
+ );
+ const nodeA = (sourceFile.statements[2] as ts.VariableStatement).declarationList.declarations[0];
+ const nodeB = (sourceFile.statements[3] as ts.VariableStatement).declarationList.declarations[0];
+ const typeA = typeChecker.getTypeAtLocation(nodeA);
+ const typeB = typeChecker.getTypeAtLocation(nodeB);
+
+ expect(
+ couldBeType(typeA, 'A', {
+ name: /"\/a"/,
+ typeChecker,
+ }),
+ ).toBe(true);
+ expect(
+ couldBeType(typeB, 'B', {
+ name: /b/,
+ typeChecker,
+ }),
+ ).toBe(false);
+ });
+});
diff --git a/tests/etc/create-source-file-and-type-checker.ts b/tests/etc/create-source-file-and-type-checker.ts
new file mode 100644
index 00000000..5810a611
--- /dev/null
+++ b/tests/etc/create-source-file-and-type-checker.ts
@@ -0,0 +1,50 @@
+import * as tsvfs from '@typescript/vfs';
+import ts from 'typescript';
+
+interface SourceFileAndTypeChecker {
+ sourceFile: ts.SourceFile;
+ typeChecker: ts.TypeChecker;
+}
+
+export function createSourceFileAndTypeChecker(
+ sourceText: string,
+ fileName = 'file.tsx',
+): SourceFileAndTypeChecker {
+ const compilerOptions: ts.CompilerOptions = {
+ lib: ['ES2018'],
+ target: ts.ScriptTarget.ES2018,
+ module: ts.ModuleKind.CommonJS,
+ };
+
+ const fsMap = tsvfs.createDefaultMapFromNodeModules(compilerOptions, ts);
+ fsMap.set(fileName, sourceText);
+ fsMap.set('/a.ts', 'export class A {}');
+ fsMap.set('/b.ts', 'export class B {}');
+
+ const system = tsvfs.createSystem(fsMap);
+ const env = tsvfs.createVirtualTypeScriptEnvironment(
+ system,
+ [fileName, '/a.ts', '/b.ts'],
+ ts,
+ compilerOptions,
+ );
+
+ const program = env.languageService.getProgram();
+ if (program === undefined) {
+ throw new Error('Failed to get program');
+ }
+ // Note: If you're having trouble with vfs, run the tests with DEBUG=1 for more output.
+ const fileIssues = env.languageService.getSemanticDiagnostics(fileName);
+ if (fileIssues.length) {
+ throw new Error(fileIssues
+ .map(diag => diag.messageText)
+ .map(msg => typeof msg === 'string' ? msg : msg.messageText)
+ .join());
+ }
+
+ return {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ sourceFile: program.getSourceFile(fileName)!,
+ typeChecker: program.getTypeChecker(),
+ };
+}
diff --git a/tests/etc/from-fixture.ts b/tests/etc/from-fixture.ts
new file mode 100644
index 00000000..b012602f
--- /dev/null
+++ b/tests/etc/from-fixture.ts
@@ -0,0 +1,107 @@
+import { InvalidTestCase, SuggestionOutput, TestCaseError } from '@typescript-eslint/rule-tester';
+import { TSESLint } from '@typescript-eslint/utils';
+
+export function fromFixture<
+ TMessageIds extends string,
+>(
+ fixture: string,
+ invalidTestCase?: {
+ output?: string;
+ suggestions?: readonly SuggestionOutput[] | null;
+ },
+): InvalidTestCase;
+export function fromFixture<
+ TMessageIds extends string,
+ TOptions extends readonly unknown[],
+>(
+ fixture: string,
+ invalidTestCase: Omit<
+ InvalidTestCase,
+ 'code' | 'errors'
+ > & {
+ suggestions?: readonly SuggestionOutput[] | null;
+ }
+): InvalidTestCase;
+export function fromFixture<
+ TMessageIds extends string,
+ TOptions extends readonly unknown[],
+>(
+ fixture: string,
+ invalidTestCase: Omit<
+ InvalidTestCase,
+ 'code' | 'errors'
+ > & {
+ suggestions?: readonly SuggestionOutput[] | null;
+ } = {},
+): InvalidTestCase {
+ const { suggestions, ...rest } = invalidTestCase;
+ return {
+ ...rest,
+ ...parseFixture(fixture, suggestions),
+ };
+}
+
+function getSuggestions(
+ suggestions:
+ | readonly SuggestionOutput[]
+ | null
+ | undefined,
+ suggest: boolean,
+ indices: string | undefined,
+) {
+ if (!suggestions || !suggest) {
+ return {};
+ }
+ if (!indices) {
+ return { suggestions } as const;
+ }
+ return {
+ suggestions: indices
+ .split(/\s+/)
+ .map((index) => suggestions[Number.parseInt(index, 10)]),
+ } as const;
+}
+
+function parseFixture(
+ fixture: string,
+ suggestions?: readonly SuggestionOutput[] | null,
+) {
+ const errorRegExp
+ = /^(?\s*)(?~+)\s*\[(?\w+)\s*(?.*?)(?:\s*(?suggest)\s*(?[\d\s]*))?\]\s*$/;
+ const lines: string[] = [];
+ const errors: TestCaseError[] = [];
+ let suggestFound = false;
+ fixture.split('\n').forEach((line) => {
+ const match = errorRegExp.exec(line);
+ if (match?.groups) {
+ const column = match.groups.indent.length + 1;
+ const endColumn = column + match.groups.error.length;
+ const { length } = lines;
+ errors.push({
+ column,
+ data: JSON.parse(match.groups.data || '{}') as TSESLint.ReportDescriptorMessageData,
+ endColumn,
+ endLine: length,
+ line: length,
+ messageId: match.groups.id as TMessageIds,
+ ...getSuggestions(
+ suggestions,
+ Boolean(match.groups.suggest),
+ match.groups.indices?.trim(),
+ ),
+ });
+ if (match.groups.suggest) {
+ suggestFound = true;
+ }
+ } else {
+ lines.push(line);
+ }
+ });
+ if (suggestions && !suggestFound) {
+ throw new Error('Suggestions specified but no \'suggest\' annotation found.');
+ }
+ return {
+ code: lines.join('\n'),
+ errors,
+ };
+}
diff --git a/tests/etc/index.ts b/tests/etc/index.ts
new file mode 100644
index 00000000..0bf29cb7
--- /dev/null
+++ b/tests/etc/index.ts
@@ -0,0 +1 @@
+export * from './from-fixture';
diff --git a/tests/package.test.ts b/tests/package.test.ts
new file mode 100644
index 00000000..aa388512
--- /dev/null
+++ b/tests/package.test.ts
@@ -0,0 +1,80 @@
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import plugin from '../src';
+
+function isSourceFile(value: string): boolean {
+ const ext = path.extname(value);
+ return ext === '.ts' && !value.endsWith('.d.ts');
+}
+
+describe('package', () => {
+ const pkg = path.resolve('src');
+
+ it('exists', () => {
+ expect(plugin).toBeDefined();
+ });
+
+ it('has every rule', async () => {
+ const files = await fs.readdir(path.resolve(pkg, 'rules'));
+ for (const file of files.filter(isSourceFile)) {
+ const ruleName = path.basename(file, path.extname(file));
+ expect(plugin.rules).toHaveProperty(ruleName);
+ }
+ });
+
+ it('exports all configs', async () => {
+ const files = await fs.readdir(path.resolve(pkg, 'configs'));
+ for (const file of files.filter(isSourceFile)) {
+ const configName = path.basename(file, path.extname(file));
+ expect(plugin.configs).toHaveProperty(configName);
+ }
+ });
+
+ it('has configs only for rules included in the plugin', () => {
+ if (!plugin.configs) {
+ expect.fail('No configs found.');
+ }
+
+ const namespace = 'rxjs-x';
+ for (const config of Object.values(plugin.configs)) {
+ if (!config.rules) {
+ continue;
+ }
+ for (const ruleName of Object.keys(config.rules)) {
+ expect(plugin.rules).toHaveProperty(ruleName.slice(namespace.length + 1));
+ }
+ }
+ });
+
+ it.for(Object.keys(plugin.rules))('includes rule %s in configurations based on meta.docs.recommended', (ruleName, { expect }) => {
+ const rule = plugin.rules[ruleName as keyof typeof plugin.rules];
+ const namespace = 'rxjs-x';
+ const fullRuleName = `${namespace}/${ruleName}`;
+
+ if (!rule.meta.docs?.recommended) {
+ // Rule is not included in any configuration.
+ expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName);
+ expect(plugin.configs.strict.rules).not.toHaveProperty(fullRuleName);
+ } else if (typeof rule.meta.docs.recommended === 'string') {
+ // Rule specifies only a configuration name.
+ expect(rule.meta.docs.recommended).toMatch(/^(recommended|strict)$/);
+ if (rule.meta.docs.recommended === 'recommended') {
+ expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName);
+ } else {
+ expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName);
+ }
+
+ // Strict configuration always includes all recommended rules.
+ // Not allowed to specify non-default options since rule only specifies a configuration name.
+ expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName, expect.any(String));
+ } else {
+ // Rule specifies non-default options for strict.
+ if (rule.meta.docs.recommended.recommended) {
+ expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName);
+ } else {
+ expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName);
+ }
+ expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName, [expect.any(String), rule.meta.docs.recommended.strict[0]]);
+ }
+ });
+});
diff --git a/tests/rule-tester.ts b/tests/rule-tester.ts
new file mode 100644
index 00000000..cfb8188c
--- /dev/null
+++ b/tests/rule-tester.ts
@@ -0,0 +1,27 @@
+import path from 'node:path';
+import { RuleTester } from '@typescript-eslint/rule-tester';
+import { parser as tseslintParser } from 'typescript-eslint';
+import * as vitest from 'vitest';
+
+RuleTester.afterAll = vitest.afterAll;
+RuleTester.it = vitest.it;
+RuleTester.itOnly = vitest.it.only;
+RuleTester.describe = vitest.describe;
+
+export function ruleTester({ typeScript = true, types = true, jsx = false } = {}) {
+ return new RuleTester({
+ languageOptions: {
+ parser: typeScript ? tseslintParser : undefined,
+ parserOptions: {
+ projectService: typeScript && types ? {
+ allowDefaultProject: ['*.ts*'],
+ defaultProject: 'tsconfig.json',
+ } : undefined,
+ tsconfigRootDir: path.join(__dirname, '..'),
+ ecmaFeatures: {
+ jsx,
+ },
+ },
+ },
+ });
+}
diff --git a/tests/rules/ban-observables.ts b/tests/rules/ban-observables.test.ts
similarity index 51%
rename from tests/rules/ban-observables.ts
rename to tests/rules/ban-observables.test.ts
index 4bf3303e..3de72e4c 100644
--- a/tests/rules/ban-observables.ts
+++ b/tests/rules/ban-observables.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { banObservablesRule } from '../../src/rules/ban-observables';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/ban-observables");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("ban-observables", rule, {
+ruleTester({ types: false }).run('ban-observables', banObservablesRule, {
valid: [
{
code: `import { of, Observable } from "rxjs";`,
@@ -25,11 +20,11 @@ ruleTester({ types: false }).run("ban-observables", rule, {
options: [
{
of: true,
- Observable: "because I say so",
+ Observable: 'because I say so',
Subject: false,
},
],
- }
+ },
),
],
});
diff --git a/tests/rules/ban-operators.test.ts b/tests/rules/ban-operators.test.ts
new file mode 100644
index 00000000..ac62ec3b
--- /dev/null
+++ b/tests/rules/ban-operators.test.ts
@@ -0,0 +1,134 @@
+import { stripIndent } from 'common-tags';
+import { banOperatorsRule } from '../../src/rules/ban-operators';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('ban-operators', banOperatorsRule, {
+ valid: [
+ {
+ code: stripIndent`
+ // root import
+ import { of, concat, merge as m, mergeMap as mm } from "rxjs";
+
+ of('a').pipe(concat(of('b')));
+ of(1).pipe(m(of(2)));
+ of('a').pipe(mm(x => of(x + '1')));
+ `,
+ options: [{}],
+ },
+ {
+ code: stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+
+ Rx.of('a').pipe(Rx.concat(Rx.of('b')));
+ Rx.of(1).pipe(Rx.merge(Rx.of(2)));
+ Rx.of('a').pipe(Rx.mergeMap(x => Rx.of(x + '1')));
+ `,
+ options: [{}],
+ },
+ {
+ code: stripIndent`
+ // operators path import (deprecated)
+ import { of, concat, merge as m, mergeMap as mm } from "rxjs/operators";
+
+ of('a').pipe(concat(of('b')));
+ of(1).pipe(m(of(2)));
+ of('a').pipe(mm(x => of(x + '1')));
+ `,
+ options: [{}],
+ },
+ stripIndent`
+ // no options
+ import { of, concat } from "rxjs";
+
+ of('a').pipe(concat(of('b')));
+ `,
+ {
+ code: stripIndent`
+ // non-RxJS operator
+ import { of } from "rxjs";
+
+ function concat() {}
+
+ of('a').pipe(concat());
+ `,
+ options: [{ concat: true }],
+ },
+ {
+ code: stripIndent`
+ // only within pipe
+ import { of, concat } from "rxjs";
+
+ // For performance reasons, we don't lint operators used outside of pipe.
+ concat(of('a'));
+ `,
+ options: [{ concat: true }],
+ },
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // root import
+ import { of, concat, merge as m, mergeMap as mm } from "rxjs";
+
+ of('a').pipe(concat(of('b')));
+ ~~~~~~ [forbidden { "name": "concat", "explanation": "" }]
+ of(1).pipe(m(of(2)));
+ ~ [forbidden { "name": "merge", "explanation": ": because I say so" }]
+ of('a').pipe(mm(x => of(x + '1')));
+ `,
+ {
+ options: [
+ {
+ concat: true,
+ merge: 'because I say so',
+ mergeMap: false,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+
+ Rx.of('a').pipe(Rx.concat(Rx.of('b')));
+ ~~~~~~ [forbidden { "name": "concat", "explanation": "" }]
+ Rx.of(1).pipe(Rx.merge(Rx.of(2)));
+ ~~~~~ [forbidden { "name": "merge", "explanation": "" }]
+ Rx.of('a').pipe(Rx.mergeMap(x => Rx.of(x + '1')));
+ `,
+ {
+ options: [
+ {
+ concat: true,
+ merge: true,
+ mergeMap: false,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // operators path import (deprecated)
+ import { of, concat, merge as m, mergeMap as mm } from "rxjs/operators";
+
+ of('a').pipe(concat(of('b')));
+ ~~~~~~ [forbidden { "name": "concat", "explanation": "" }]
+ of(1).pipe(m(of(2)));
+ ~ [forbidden { "name": "merge", "explanation": ": because I say so" }]
+ of('a').pipe(mm(x => of(x + '1')));
+ `,
+ {
+ options: [
+ {
+ concat: true,
+ merge: 'because I say so',
+ mergeMap: false,
+ },
+ ],
+ },
+ ),
+ ],
+});
diff --git a/tests/rules/ban-operators.ts b/tests/rules/ban-operators.ts
deleted file mode 100644
index 0332c7d4..00000000
--- a/tests/rules/ban-operators.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/ban-operators");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("ban-operators", rule, {
- valid: [
- {
- code: `import { concat, merge as m, mergeMap as mm } from "rxjs/operators";`,
- },
- {
- code: `import { concat, merge as m, mergeMap as mm } from "rxjs";`,
- },
- {
- // This won't effect errors, because only imports from "rxjs/operators"
- // are checked. To support banning operators from "rxjs", it'll need to
- // check types.
- code: `import { concat, merge as m, mergeMap as mm } from "rxjs";`,
- options: [
- {
- concat: true,
- merge: "because I say so",
- mergeMap: false,
- },
- ],
- },
- ],
- invalid: [
- fromFixture(
- stripIndent`
- import { concat, merge as m, mergeMap as mm } from "rxjs/operators";
- ~~~~~~ [forbidden { "name": "concat", "explanation": "" }]
- ~~~~~ [forbidden { "name": "merge", "explanation": ": because I say so" }]
- `,
- {
- options: [
- {
- concat: true,
- merge: "because I say so",
- mergeMap: false,
- },
- ],
- }
- ),
- ],
-});
diff --git a/tests/rules/finnish.ts b/tests/rules/finnish.test.ts
similarity index 94%
rename from tests/rules/finnish.ts
rename to tests/rules/finnish.test.ts
index 2edf6c83..562237f2 100644
--- a/tests/rules/finnish.ts
+++ b/tests/rules/finnish.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { finnishRule } from '../../src/rules/finnish';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/finnish");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("finnish", rule, {
+ruleTester({ types: true }).run('finnish', finnishRule, {
valid: [
{
code: stripIndent`
@@ -106,7 +101,7 @@ ruleTester({ types: true }).run("finnish", rule, {
options: [
{
types: {
- "^EventEmitter$": false,
+ '^EventEmitter$': false,
},
},
],
@@ -123,7 +118,7 @@ ruleTester({ types: true }).run("finnish", rule, {
{
strict: true,
types: {
- "^EventEmitter$": false,
+ '^EventEmitter$': false,
},
},
],
@@ -210,7 +205,7 @@ ruleTester({ types: true }).run("finnish", rule, {
const someOptionalObservable: Observable | undefined = of();
~~~~~~~~~~~~~~~~~~~~~~ [shouldBeFinnish]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -231,16 +226,16 @@ ruleTester({ types: true }).run("finnish", rule, {
options: [
{
names: {
- "^finnish$": true,
- "^foreign$": false,
+ '^finnish$': true,
+ '^foreign$': false,
},
types: {
- "^EventEmitter$": false,
- "^SomeSubject$": true,
+ '^EventEmitter$': false,
+ '^SomeSubject$': true,
},
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -258,12 +253,12 @@ ruleTester({ types: true }).run("finnish", rule, {
options: [
{
types: {
- "^EventEmitter$": false,
- "^SomeSubject$": true,
+ '^EventEmitter$': false,
+ '^SomeSubject$': true,
},
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -274,7 +269,7 @@ ruleTester({ types: true }).run("finnish", rule, {
const someArray = [someObservable$];
function someFunction(someParam$: Observable): Observable { return someParam$; }
~~~~~~~~~~~~ [shouldBeFinnish]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -290,7 +285,7 @@ ruleTester({ types: true }).run("finnish", rule, {
someMethod(someParam$: Observable): Observable;
~~~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -324,7 +319,7 @@ ruleTester({ types: true }).run("finnish", rule, {
(someParam: Observable): void;
~~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -349,7 +344,7 @@ ruleTester({ types: true }).run("finnish", rule, {
someProperty: Observable;
~~~~~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -368,7 +363,7 @@ ruleTester({ types: true }).run("finnish", rule, {
const someArray = [someObservable];
const [someElement] = someArray;
~~~~~~~~~~~ [shouldBeFinnish]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -384,7 +379,7 @@ ruleTester({ types: true }).run("finnish", rule, {
const someArray = [someObservable];
const [someElement] = someArray;
`,
- { options: [{ variables: false }] }
+ { options: [{ variables: false }] },
),
fromFixture(
stripIndent`
@@ -405,7 +400,7 @@ ruleTester({ types: true }).run("finnish", rule, {
(someParam: Observable): void;
~~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -425,7 +420,7 @@ ruleTester({ types: true }).run("finnish", rule, {
~~~~~~~~~~ [shouldBeFinnish]
(someValue: any): Observable;
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -439,7 +434,7 @@ ruleTester({ types: true }).run("finnish", rule, {
someMethod([someParam]: Observable[]): void {}
~~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -453,7 +448,7 @@ ruleTester({ types: true }).run("finnish", rule, {
someMethod({ source }: Record>): void {}
~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -464,7 +459,7 @@ ruleTester({ types: true }).run("finnish", rule, {
constructor(public someProp: Observable) {}
~~~~~~~~ [shouldBeFinnish]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -472,7 +467,7 @@ ruleTester({ types: true }).run("finnish", rule, {
const answer$ = 42;
~~~~~~~ [shouldNotBeFinnish]
`,
- { options: [{ strict: true }] }
+ { options: [{ strict: true }] },
),
],
});
diff --git a/tests/rules/just.ts b/tests/rules/just.test.ts
similarity index 81%
rename from tests/rules/just.ts
rename to tests/rules/just.test.ts
index e6c10b45..89c4efc0 100644
--- a/tests/rules/just.ts
+++ b/tests/rules/just.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { justRule } from '../../src/rules/just';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/just");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("just", rule, {
+ruleTester({ types: true }).run('just', justRule, {
valid: [
stripIndent`
// non-RxJS of
@@ -59,7 +54,7 @@ ruleTester({ types: true }).run("just", rule, {
const a = just("a");
const b = just("b");
`,
- }
+ },
),
fromFixture(
stripIndent`
@@ -100,7 +95,7 @@ ruleTester({ types: true }).run("just", rule, {
of();
}
`,
- }
+ },
),
],
});
diff --git a/tests/rules/macro.ts b/tests/rules/macro.test.ts
similarity index 79%
rename from tests/rules/macro.ts
rename to tests/rules/macro.test.ts
index 0076d90e..83db7c11 100644
--- a/tests/rules/macro.ts
+++ b/tests/rules/macro.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { macroRule } from '../../src/rules/macro';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/macro");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("macro", rule, {
+ruleTester({ types: true }).run('macro', macroRule, {
valid: [
stripIndent`
// no macro; no RxJS
@@ -45,7 +40,7 @@ ruleTester({ types: true }).run("macro", rule, {
import "babel-plugin-rxjs-tools/macro";
import { of } from "rxjs";
`,
- }
+ },
),
fromFixture(
stripIndent`
@@ -61,7 +56,7 @@ ruleTester({ types: true }).run("macro", rule, {
import { foo, goo } from "bar";
const hoo = foo.pipe(goo());
`,
- }
+ },
),
fromFixture(
stripIndent`
@@ -77,7 +72,7 @@ ruleTester({ types: true }).run("macro", rule, {
import { foo } from "bar";
foo.subscribe();
`,
- }
+ },
),
],
});
diff --git a/tests/rules/no-async-subscribe.ts b/tests/rules/no-async-subscribe.test.ts
similarity index 58%
rename from tests/rules/no-async-subscribe.ts
rename to tests/rules/no-async-subscribe.test.ts
index fd62dec8..15e39997 100644
--- a/tests/rules/no-async-subscribe.ts
+++ b/tests/rules/no-async-subscribe.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noAsyncSubscribeRule } from '../../src/rules/no-async-subscribe';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-async-subscribe");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-async-subscribe", rule, {
+ruleTester({ types: true }).run('no-async-subscribe', noAsyncSubscribeRule, {
valid: [
stripIndent`
// sync arrow function
@@ -22,12 +17,15 @@ ruleTester({ types: true }).run("no-async-subscribe", rule, {
of("a").subscribe(function() {});
`,
- stripIndent`
- // https://github.com/cartant/eslint-plugin-rxjs/issues/46
- import React, { FC } from "react";
- const SomeComponent: FC<{}> = () => some component;
- const someElement = ;
- `,
+ {
+ code: stripIndent`
+ // https://github.com/cartant/eslint-plugin-rxjs/issues/46
+ import React, { FC } from "react";
+ const SomeComponent: FC<{}> = () => some component;
+ const someElement = ;
+ `,
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ },
stripIndent`
// https://github.com/cartant/eslint-plugin-rxjs/issues/61
const whatever = {
@@ -46,7 +44,7 @@ ruleTester({ types: true }).run("no-async-subscribe", rule, {
~~~~~ [forbidden]
return await "a";
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -57,7 +55,7 @@ ruleTester({ types: true }).run("no-async-subscribe", rule, {
~~~~~ [forbidden]
return await "a";
});
- `
+ `,
),
],
});
diff --git a/tests/rules/no-compat.ts b/tests/rules/no-compat.test.ts
similarity index 77%
rename from tests/rules/no-compat.ts
rename to tests/rules/no-compat.test.ts
index 62cabf1e..45bf85ae 100644
--- a/tests/rules/no-compat.ts
+++ b/tests/rules/no-compat.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noCompatRule } from '../../src/rules/no-compat';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-compat");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-compat", rule, {
+ruleTester({ types: false }).run('no-compat', noCompatRule, {
valid: [
`import { Observable } from "rxjs";`,
`import { ajax } from "rxjs/ajax";`,
@@ -23,49 +18,49 @@ ruleTester({ types: false }).run("no-compat", rule, {
stripIndent`
import * as Rx from "rxjs/Rx";
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import { Observable } from "rxjs/Observable";
~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import { Subject } from "rxjs/Subject";
~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import { merge } from "rxjs/observable/merge";
~~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import { merge } from "rxjs/operator/merge";
~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import { asap } from "rxjs/scheduler/asap";
~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import "rxjs/add/observable/merge";
~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
import "rxjs/add/operator/mergeMap";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-connectable.ts b/tests/rules/no-connectable.test.ts
similarity index 86%
rename from tests/rules/no-connectable.ts
rename to tests/rules/no-connectable.test.ts
index b417685b..586a66b7 100644
--- a/tests/rules/no-connectable.ts
+++ b/tests/rules/no-connectable.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noConnectableRule } from '../../src/rules/no-connectable';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-connectable");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-connectable", rule, {
+ruleTester({ types: true }).run('no-connectable', noConnectableRule, {
valid: [
{
code: stripIndent`
@@ -67,7 +62,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
publish()
~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -78,7 +73,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
publishBehavior(1)
~~~~~~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -89,7 +84,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
publishLast()
~~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -100,7 +95,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
publishReplay(1)
~~~~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -111,7 +106,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
multicast(new Subject())
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -122,7 +117,7 @@ ruleTester({ types: true }).run("no-connectable", rule, {
multicast(() => new Subject())
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
],
});
diff --git a/tests/rules/no-create.test.ts b/tests/rules/no-create.test.ts
new file mode 100644
index 00000000..7c55a1a7
--- /dev/null
+++ b/tests/rules/no-create.test.ts
@@ -0,0 +1,23 @@
+import { stripIndent } from 'common-tags';
+import { noCreateRule } from '../../src/rules/no-create';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-create', noCreateRule, {
+ valid: [],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // create
+ import { Observable, Observer } from "rxjs";
+
+ const ob = Observable.create((observer: Observer) => {
+ ~~~~~~ [forbidden]
+ observer.next("Hello, world.");
+ observer.complete();
+ return () => {};
+ });
+ `,
+ ),
+ ],
+});
diff --git a/tests/rules/no-create.ts b/tests/rules/no-create.ts
deleted file mode 100644
index 406b743f..00000000
--- a/tests/rules/no-create.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-create");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-create", rule, {
- valid: [],
- invalid: [
- fromFixture(
- stripIndent`
- // create
- import { Observable, Observer } from "rxjs";
-
- const ob = Observable.create((observer: Observer) => {
- ~~~~~~ [forbidden]
- observer.next("Hello, world.");
- observer.complete();
- return () => {};
- });
- `
- ),
- ],
-});
diff --git a/tests/rules/no-cyclic-action.ts b/tests/rules/no-cyclic-action.test.ts
similarity index 61%
rename from tests/rules/no-cyclic-action.ts
rename to tests/rules/no-cyclic-action.test.ts
index 1591aeec..d9d8ab6c 100644
--- a/tests/rules/no-cyclic-action.ts
+++ b/tests/rules/no-cyclic-action.test.ts
@@ -1,16 +1,11 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-cyclic-action");
-import { ruleTester } from "../utils";
+import { stripIndent } from 'common-tags';
+import { noCyclicActionRule } from '../../src/rules/no-cyclic-action';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
const setup = stripIndent`
import { Observable, of } from "rxjs";
- import { mapTo } from "rxjs/operators";
+ import { map } from "rxjs/operators";
type Action = { type: T };
type ActionOfType = T extends string ? Action : never;
@@ -24,28 +19,28 @@ const setup = stripIndent`
const SOMETHING = "SOMETHING";
const SOMETHING_ELSE = "SOMETHING_ELSE";
-`.replace(/\n/g, "");
+`.replace(/\n/g, '');
-ruleTester({ types: true }).run("no-cyclic-action", rule, {
+ruleTester({ types: true }).run('no-cyclic-action', noCyclicActionRule, {
valid: [
{
code: stripIndent`
// effect SOMETHING to SOMETHING_ELSE
${setup}
- const a = actions.pipe(ofType("SOMETHING"), mapTo({ type: "SOMETHING_ELSE" as const }));
- const b = actions.pipe(ofType("SOMETHING"), mapTo({ type: SOMETHING_ELSE } as const));
- const c = actions.pipe(ofType(SOMETHING), mapTo({ type: "SOMETHING_ELSE" as const }));
- const d = actions.pipe(ofType(SOMETHING), mapTo({ type: SOMETHING_ELSE } as const));
+ const a = actions.pipe(ofType("SOMETHING"), map(() => ({ type: "SOMETHING_ELSE" as const })));
+ const b = actions.pipe(ofType("SOMETHING"), map(() => ({ type: SOMETHING_ELSE }) as const));
+ const c = actions.pipe(ofType(SOMETHING), map(() => ({ type: "SOMETHING_ELSE" as const })));
+ const d = actions.pipe(ofType(SOMETHING), map(() => ({ type: SOMETHING_ELSE }) as const));
`,
},
{
code: stripIndent`
// epic SOMETHING to SOMETHING_ELSE
${setup}
- const a = (action$: Actions) => action$.pipe(ofType("SOMETHING"), mapTo({ type: "SOMETHING_ELSE" as const }));
- const b = (action$: Actions) => action$.pipe(ofType("SOMETHING"), mapTo({ type: SOMETHING_ELSE } as const));
- const c = (action$: Actions) => action$.pipe(ofType(SOMETHING), mapTo({ type: "SOMETHING_ELSE" as const }));
- const d = (action$: Actions) => action$.pipe(ofType(SOMETHING), mapTo({ type: SOMETHING_ELSE } as const));
+ const a = (action$: Actions) => action$.pipe(ofType("SOMETHING"), map(() => ({ type: "SOMETHING_ELSE" as const })));
+ const b = (action$: Actions) => action$.pipe(ofType("SOMETHING"), map(() => ({ type: SOMETHING_ELSE }) as const));
+ const c = (action$: Actions) => action$.pipe(ofType(SOMETHING), map(() => ({ type: "SOMETHING_ELSE" as const })));
+ const d = (action$: Actions) => action$.pipe(ofType(SOMETHING), map(() => ({ type: SOMETHING_ELSE }) as const));
`,
},
{
@@ -61,57 +56,57 @@ ruleTester({ types: true }).run("no-cyclic-action", rule, {
stripIndent`
// effect SOMETHING to SOMETHING
${setup}
- const a = actions.pipe(ofType("SOMETHING"), mapTo({ type: "SOMETHING" as const }));
+ const a = actions.pipe(ofType("SOMETHING"), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const b = actions.pipe(ofType("SOMETHING"), mapTo({ type: SOMETHING } as const));
+ const b = actions.pipe(ofType("SOMETHING"), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- const c = actions.pipe(ofType(SOMETHING), mapTo({ type: "SOMETHING" as const }));
+ const c = actions.pipe(ofType(SOMETHING), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const d = actions.pipe(ofType(SOMETHING), mapTo({ type: SOMETHING } as const));
+ const d = actions.pipe(ofType(SOMETHING), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
// epic SOMETHING to SOMETHING
${setup}
- const a = (action$: Actions) => action$.pipe(ofType("SOMETHING"), mapTo({ type: "SOMETHING" as const }));
+ const a = (action$: Actions) => action$.pipe(ofType("SOMETHING"), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const b = (action$: Actions) => action$.pipe(ofType("SOMETHING"), mapTo({ type: SOMETHING } as const));
+ const b = (action$: Actions) => action$.pipe(ofType("SOMETHING"), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- const c = (action$: Actions) => action$.pipe(ofType(SOMETHING), mapTo({ type: "SOMETHING" as const }));
+ const c = (action$: Actions) => action$.pipe(ofType(SOMETHING), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const d = (action$: Actions) => action$.pipe(ofType(SOMETHING), mapTo({ type: SOMETHING } as const));
+ const d = (action$: Actions) => action$.pipe(ofType(SOMETHING), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
// effect SOMETHING | SOMETHING_ELSE to SOMETHING
${setup}
- const a = actions.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), mapTo({ type: "SOMETHING" as const }));
+ const a = actions.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const b = actions.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), mapTo({ type: SOMETHING } as const));
+ const b = actions.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- const c = actions.pipe(ofType(SOMETHING, SOMETHING_ELSE), mapTo({ type: "SOMETHING" as const }));
+ const c = actions.pipe(ofType(SOMETHING, SOMETHING_ELSE), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const d = actions.pipe(ofType(SOMETHING, SOMETHING_ELSE), mapTo({ type: SOMETHING } as const));
+ const d = actions.pipe(ofType(SOMETHING, SOMETHING_ELSE), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
// epic SOMETHING | SOMETHING_ELSE to SOMETHING
${setup}
- const a = (action$: Actions) => action$.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), mapTo({ type: "SOMETHING" as const }));
+ const a = (action$: Actions) => action$.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const b = (action$: Actions) => action$.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), mapTo({ type: SOMETHING } as const));
+ const b = (action$: Actions) => action$.pipe(ofType("SOMETHING", "SOMETHING_ELSE"), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- const c = (action$: Actions) => action$.pipe(ofType(SOMETHING, SOMETHING_ELSE), mapTo({ type: "SOMETHING" as const }));
+ const c = (action$: Actions) => action$.pipe(ofType(SOMETHING, SOMETHING_ELSE), map(() => ({ type: "SOMETHING" as const })));
~~~~~~~~~~~~ [forbidden]
- const d = (action$: Actions) => action$.pipe(ofType(SOMETHING, SOMETHING_ELSE), mapTo({ type: SOMETHING } as const));
+ const d = (action$: Actions) => action$.pipe(ofType(SOMETHING, SOMETHING_ELSE), map(() => ({ type: SOMETHING }) as const));
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-explicit-generics.ts b/tests/rules/no-explicit-generics.test.ts
similarity index 82%
rename from tests/rules/no-explicit-generics.ts
rename to tests/rules/no-explicit-generics.test.ts
index 3d1d5c5f..e7b76b3e 100644
--- a/tests/rules/no-explicit-generics.ts
+++ b/tests/rules/no-explicit-generics.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noExplicitGenericsRule } from '../../src/rules/no-explicit-generics';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-explicit-generics");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-explicit-generics", rule, {
+ruleTester({ types: false }).run('no-explicit-generics', noExplicitGenericsRule, {
valid: [
{
code: stripIndent`
@@ -53,31 +48,31 @@ ruleTester({ types: false }).run("no-explicit-generics", rule, {
scan((acc, value) => acc + value, "")
~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
const b = new BehaviorSubject(42);
~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
const f = from([42, 54]);
~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
const o = of(42, 54);
~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
const n = new Notification("N", 42);
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-exposed-subjects.ts b/tests/rules/no-exposed-subjects.test.ts
similarity index 90%
rename from tests/rules/no-exposed-subjects.ts
rename to tests/rules/no-exposed-subjects.test.ts
index 59f54484..9e50b792 100644
--- a/tests/rules/no-exposed-subjects.ts
+++ b/tests/rules/no-exposed-subjects.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noExposedSubjectsRule } from '../../src/rules/no-exposed-subjects';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-exposed-subjects");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-exposed-subjects", rule, {
+ruleTester({ types: true }).run('no-exposed-subjects', noExposedSubjectsRule, {
valid: [
stripIndent`
// variable
@@ -98,7 +93,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
readonly e = new Subject();
~ [forbidden { "subject": "e" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -113,7 +108,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
~ [forbidden { "subject": "b" }]
) {}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -131,7 +126,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
this._submitSubject$ = set$;
}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -149,7 +144,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
return new Subject();
}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -181,7 +176,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
}
}
`,
- { options: [{ allowProtected: true }] }
+ { options: [{ allowProtected: true }] },
),
fromFixture(
stripIndent`
@@ -198,7 +193,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
protected d: Subject;
~ [forbidden { "subject": "d" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -215,7 +210,7 @@ ruleTester({ types: true }).run("no-exposed-subjects", rule, {
return this.foo$;
}
}
- `
+ `,
),
],
});
diff --git a/tests/rules/no-finnish.ts b/tests/rules/no-finnish.test.ts
similarity index 93%
rename from tests/rules/no-finnish.ts
rename to tests/rules/no-finnish.test.ts
index 8fca1700..bd7e983e 100644
--- a/tests/rules/no-finnish.ts
+++ b/tests/rules/no-finnish.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noFinnishRule } from '../../src/rules/no-finnish';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-finnish");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-finnish", rule, {
+ruleTester({ types: true }).run('no-finnish', noFinnishRule, {
valid: [
stripIndent`
// without $
@@ -63,7 +58,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
~~~~~~~~~~~~~~~~~~ [forbidden]
const [{ someKey$: yetAnotherObservable$ }] = [someObject];
~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -78,7 +73,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
~~~~~~~~ [forbidden]
const { someKey$: someRenamedKey$ } = someObject;
~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -93,7 +88,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
~~~~~~~~ [forbidden]
someArray.forEach((element$: Observable) => {});
~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -105,7 +100,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
const someArrowFunction$ = (someParam$: Observable): Observable => someParam$;
~~~~~~~~~~~~~~~~~~ [forbidden]
~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -125,7 +120,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
~~~~~~~~~~~ [forbidden]
~~~~~~~~~~ [forbidden]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -142,7 +137,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
(someParam$: Observable): void;
~~~~~~~~~~ [forbidden]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -163,7 +158,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
(someParam$: Observable): void;
~~~~~~~~~~ [forbidden]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -183,7 +178,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
~~~~~~~~~~~ [forbidden]
(someValue: any): Observable;
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -197,7 +192,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
someMethod([someParam$]: Observable[]): void {}
~~~~~~~~~~ [forbidden]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -210,7 +205,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
someMethod({ source$ }: Record>): void {}
~~~~~~~ [forbidden]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -221,7 +216,7 @@ ruleTester({ types: true }).run("no-finnish", rule, {
constructor(public someProp$: Observable) {}
~~~~~~~~~ [forbidden]
}
- `
+ `,
),
],
});
diff --git a/tests/rules/no-floating-observables.test.ts b/tests/rules/no-floating-observables.test.ts
new file mode 100644
index 00000000..da588408
--- /dev/null
+++ b/tests/rules/no-floating-observables.test.ts
@@ -0,0 +1,131 @@
+import { stripIndent } from 'common-tags';
+import { noFloatingObservablesRule } from '../../src/rules/no-floating-observables';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-floating-observables', noFloatingObservablesRule, {
+ valid: [
+ stripIndent`
+ // not ignored
+ import { Observable, of } from "rxjs";
+
+ function functionSource() {
+ return of(42);
+ }
+
+ function sink(source: Observable) {
+ }
+
+ functionSource().subscribe();
+ const a = functionSource();
+ const b = [functionSource()];
+ [void functionSource()];
+ sink(functionSource());
+ void functionSource();
+ `,
+ stripIndent`
+ // not ignored arrow
+ import { Observable, of } from "rxjs";
+
+ const arrowSource = () => of(42);
+
+ function sink(source: Observable) {
+ }
+
+ functionSource().subscribe();
+ const a = arrowSource();
+ const b = [arrowSource()];
+ [void arrowSource()];
+ sink(arrowSource());
+ void functionSource();
+ `,
+ stripIndent`
+ // unrelated
+ function foo() {}
+
+ [1, 2, 3, 'foo'];
+ const a = [1];
+ foo();
+ [foo()];
+ void foo();
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // ignored
+ import { Observable, of } from "rxjs";
+
+ function functionSource() {
+ return of(42);
+ }
+
+ functionSource();
+ ~~~~~~~~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // ignored arrow
+ import { Observable, of } from "rxjs";
+
+ const arrowSource = () => of(42);
+
+ arrowSource();
+ ~~~~~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // chain expression
+ import { Observable, of } from "rxjs";
+
+ const arrowSource: null | (() => Observable) = () => of(42);
+
+ arrowSource?.();
+ ~~~~~~~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // array
+ import { of } from "rxjs";
+
+ [of(42)];
+ ~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // ignoreVoid false
+ import { Observable, of } from "rxjs";
+
+ function functionSource() {
+ return of(42);
+ }
+
+ void functionSource();
+ ~~~~~~~~~~~~~~~~ [forbiddenNoVoid]
+ void functionSource?.();
+ ~~~~~~~~~~~~~~~~~~ [forbiddenNoVoid]
+ [void functionSource()];
+ ~~~~~~~~~~~~~~~~ [forbiddenNoVoid]
+ [void functionSource?.()];
+ ~~~~~~~~~~~~~~~~~~ [forbiddenNoVoid]
+ `,
+ {
+ options: [{ ignoreVoid: false }],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // sequence expression
+ import { of } from "rxjs";
+
+ of(42), of(42), void of(42);
+ ~~~~~~ [forbidden]
+ ~~~~~~ [forbidden]
+ `,
+ ),
+ ],
+});
diff --git a/tests/rules/no-ignored-default-value.test.ts b/tests/rules/no-ignored-default-value.test.ts
new file mode 100644
index 00000000..0f10483e
--- /dev/null
+++ b/tests/rules/no-ignored-default-value.test.ts
@@ -0,0 +1,166 @@
+import { stripIndent } from 'common-tags';
+import { noIgnoredDefaultValueRule } from '../../src/rules/no-ignored-default-value';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-ignored-default-value', noIgnoredDefaultValueRule, {
+ valid: [
+ stripIndent`
+ // firstValueFrom with default value
+ import { firstValueFrom, of } from "rxjs";
+
+ firstValueFrom(of(42), { defaultValue: 0 });
+ firstValueFrom(of(42), { defaultValue: null });
+ firstValueFrom(of(42), { defaultValue: undefined });
+ function getValue(obs) {
+ return firstValueFrom(obs, { defaultValue: "hello" });
+ }
+ class Foo {
+ getValue(obs) {
+ return firstValueFrom(obs, { defaultValue: "world" });
+ }
+ }
+ `,
+ stripIndent`
+ // lastValueFrom with default value
+ import { lastValueFrom, of } from "rxjs";
+
+ lastValueFrom(of(42), { defaultValue: 0 });
+ lastValueFrom(of(42), { defaultValue: null });
+ lastValueFrom(of(42), { defaultValue: undefined });
+ `,
+ stripIndent`
+ // first with default value
+ import { first, of } from "rxjs";
+
+ of(42).pipe(first(x => x, { defaultValue: 0 }));
+ of(42).pipe(first(x => x, { defaultValue: null }));
+ of(42).pipe(first(x => x, { defaultValue: undefined }));
+ `,
+ stripIndent`
+ // last with default value
+ import { last, of } from "rxjs";
+
+ of(42).pipe(last(x => x, { defaultValue: 0 }));
+ of(42).pipe(last(x => x, { defaultValue: null }));
+ of(42).pipe(last(x => x, { defaultValue: undefined }));
+ `,
+ stripIndent`
+ // other operators
+ import { of, map, filter, refCount } from "rxjs";
+
+ of(42).pipe(map(x => x), filter(x => x > 0), shareReplay({ bufferSize: 1, refCount: true }));
+ `,
+ stripIndent`
+ // non-RxJS firstValueFrom
+ import { of } from "rxjs";
+
+ function firstValueFrom(obs) {}
+ firstValueFrom(of(42));
+
+ class Foo {
+ firstValueFrom(obs) {}
+ }
+ const myFoo = new Foo();
+ myFoo.firstValueFrom(of(42));
+ `,
+ stripIndent`
+ // non-RxJS lastValueFrom
+ import { of } from "rxjs";
+
+ function lastValueFrom(obs) {}
+ lastValueFrom(of(42));
+ `,
+ stripIndent`
+ // non-RxJS first
+ import { of } from "rxjs";
+
+ function first() {}
+ of(42).pipe(first());
+ `,
+ stripIndent`
+ // non-RxJS last
+ import { of } from "rxjs";
+
+ function last() {}
+ of(42).pipe(last());
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // firstValueFrom ignored
+ import { firstValueFrom, of } from "rxjs";
+
+ firstValueFrom(of(42));
+ ~~~~~~~~~~~~~~ [forbidden]
+ firstValueFrom(of(42), {});
+ ~~ [forbidden]
+ const config = {};
+ firstValueFrom(of(42), config);
+ ~~~~~~ [forbidden]
+ const config2 = { config: {} };
+ firstValueFrom(of(42), config2.config);
+ ~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // lastValueFrom ignored
+ import { lastValueFrom, of } from "rxjs";
+
+ lastValueFrom(of(42));
+ ~~~~~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // first ignored
+ import { first, of } from "rxjs";
+
+ of(42).pipe(first());
+ ~~~~~ [forbidden]
+ of(42).pipe(first({}));
+ ~~ [forbidden]
+ const config = {};
+ of(42).pipe(first(config));
+ ~~~~~~ [forbidden]
+ const config2 = { config: {} };
+ of(42).pipe(first(config2.config));
+ ~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // last ignored
+ import { last, of } from "rxjs";
+
+ of(42).pipe(last());
+ ~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+
+ Rx.firstValueFrom(Rx.of(42));
+ ~~~~~~~~~~~~~~ [forbidden]
+ Rx.of(42).pipe(Rx.first());
+ ~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // operators import (deprecated)
+ import { of } from "rxjs";
+ import { first, last } from "rxjs/operators";
+
+ of(42).pipe(first());
+ ~~~~~ [forbidden]
+ of(42).pipe(last());
+ ~~~~ [forbidden]
+ `,
+ ),
+ ],
+});
diff --git a/tests/rules/no-ignored-error.ts b/tests/rules/no-ignored-error.test.ts
similarity index 65%
rename from tests/rules/no-ignored-error.ts
rename to tests/rules/no-ignored-error.test.ts
index 2570d7cd..49a46028 100644
--- a/tests/rules/no-ignored-error.ts
+++ b/tests/rules/no-ignored-error.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredErrorRule } from '../../src/rules/no-ignored-error';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-error");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-error", rule, {
+ruleTester({ types: true }).run('no-ignored-error', noIgnoredErrorRule, {
valid: [
stripIndent`
// noop
@@ -16,6 +11,19 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
const observable = of([1, 2]);
observable.subscribe(() => {}, () => {});
`,
+ stripIndent`
+ // observer argument
+ import { of } from "rxjs";
+
+ const observable = of([1, 2]);
+ observable.subscribe({ next: () => {}, error: () => {} });
+
+ const observer1 = { next: () => {}, error: () => {} };
+ observable.subscribe(observer1);
+
+ const obj = { observer: observer1 };
+ observable.subscribe(obj.observer);
+ `,
stripIndent`
// subject
import { Subject } from "rxjs";
@@ -42,7 +50,7 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
const observable = of([1, 2]);
observable.subscribe(() => {});
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -52,7 +60,7 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
const next = () => {};
observable.subscribe(next);
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -61,7 +69,7 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
const subject = new Subject();
subject.subscribe(() => {});
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -71,7 +79,7 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
const subject = new Subject();
subject.subscribe(next);
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -88,7 +96,23 @@ ruleTester({ types: true }).run("no-ignored-error", rule, {
return obs.subscribe((v: T) => {})
~~~~~~~~~ [forbidden]
}
- `
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // observer argument
+ import { of } from "rxjs";
+
+ const observable = of([1, 2]);
+ observable.subscribe({ next: () => {} });
+ ~~~~~~~~~ [forbidden]
+ const observer1 = { next: () => {} };
+ observable.subscribe(observer1);
+ ~~~~~~~~~ [forbidden]
+ const obj = { observer: observer1 };
+ observable.subscribe(obj.observer1);
+ ~~~~~~~~~ [forbidden]
+ `,
),
],
});
diff --git a/tests/rules/no-ignored-notifier.ts b/tests/rules/no-ignored-notifier.test.ts
similarity index 88%
rename from tests/rules/no-ignored-notifier.ts
rename to tests/rules/no-ignored-notifier.test.ts
index 971ce996..bdb2f7a2 100644
--- a/tests/rules/no-ignored-notifier.ts
+++ b/tests/rules/no-ignored-notifier.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredNotifierRule } from '../../src/rules/no-ignored-notifier';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-notifier");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-notifier", rule, {
+ruleTester({ types: true }).run('no-ignored-notifier', noIgnoredNotifierRule, {
valid: [
stripIndent`
// repeatWhen not ignored
@@ -62,7 +57,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
repeatWhen(notifications => range(0, 3))
~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -76,7 +71,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
repeatWhen(() => range(0, 3))
~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -94,7 +89,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
}
)
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -112,7 +107,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
}
)
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -126,7 +121,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
retryWhen(errors => range(0, 3))
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -140,7 +135,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
retryWhen(() => range(0, 3))
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -158,7 +153,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
}
)
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -176,7 +171,7 @@ ruleTester({ types: true }).run("no-ignored-notifier", rule, {
}
)
);
- `
+ `,
),
],
});
diff --git a/tests/rules/no-ignored-observable.ts b/tests/rules/no-ignored-observable.ts
deleted file mode 100644
index 5d103d34..00000000
--- a/tests/rules/no-ignored-observable.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-observable");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-observable", rule, {
- valid: [
- stripIndent`
- // not ignored
- import { Observable, of } from "rxjs";
-
- function functionSource() {
- return of(42);
- }
-
- function sink(source: Observable) {
- }
-
- const a = functionSource();
- sink(functionSource());
- `,
- stripIndent`
- // not ignored arrow
- import { Observable, of } from "rxjs";
-
- const arrowSource = () => of(42);
-
- function sink(source: Observable) {
- }
-
- const a = arrowSource();
- sink(arrowSource());
- `,
- ],
- invalid: [
- fromFixture(
- stripIndent`
- // ignored
- import { Observable, of } from "rxjs";
-
- function functionSource() {
- return of(42);
- }
-
- functionSource();
- ~~~~~~~~~~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // ignored arrow
- import { Observable, of } from "rxjs";
-
- const arrowSource = () => of(42);
-
- arrowSource();
- ~~~~~~~~~~~~~ [forbidden]
- `
- ),
- ],
-});
diff --git a/tests/rules/no-ignored-replay-buffer.ts b/tests/rules/no-ignored-replay-buffer.test.ts
similarity index 72%
rename from tests/rules/no-ignored-replay-buffer.ts
rename to tests/rules/no-ignored-replay-buffer.test.ts
index 6f764f6d..c57d5377 100644
--- a/tests/rules/no-ignored-replay-buffer.ts
+++ b/tests/rules/no-ignored-replay-buffer.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredReplayBufferRule } from '../../src/rules/no-ignored-replay-buffer';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-replay-buffer");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
+ruleTester({ types: false }).run('no-ignored-replay-buffer', noIgnoredReplayBufferRule, {
valid: [
stripIndent`
// ReplaySubject not ignored
@@ -31,6 +26,13 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = of(42).pipe(shareReplay(1));
`,
+ fromFixture(
+ stripIndent`
+ // shareReplay with config not ignored
+ import { interval, shareReplay } from "rxjs";
+ interval(1000).pipe(shareReplay({ bufferSize: 1, refCount: true }));
+ `,
+ ),
stripIndent`
// namespace ReplaySubject not ignored
import * as Rx from "rxjs";
@@ -52,6 +54,13 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = Rx.of(42).pipe(shareReplay(1));
`,
+ stripIndent`
+ // namespace shareReplay with config not ignored
+ import * as Rx from "rxjs";
+ import { shareReplay } from "rxjs/operators";
+
+ const a = Rx.of(42).pipe(shareReplay({ bufferSize: 1, refCount: true }));
+ `,
stripIndent`
// namespace class not ignored
import * as Rx from "rxjs";
@@ -74,7 +83,7 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
~~~~~~~~~~~~~ [forbidden]
const b = new Thing(new ReplaySubject());
~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -84,7 +93,7 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = of(42).pipe(publishReplay());
~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -94,7 +103,16 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = of(42).pipe(shareReplay());
~~~~~~~~~~~ [forbidden]
- `
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // shareReplay with config ignored
+ import { of, shareReplay } from "rxjs";
+
+ const a = of(42).pipe(shareReplay({ refCount: true }));
+ ~~~~~~~~~~~ [forbidden]
+ `,
),
fromFixture(
stripIndent`
@@ -105,7 +123,7 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
~~~~~~~~~~~~~ [forbidden]
const b = new Thing(new Rx.ReplaySubject());
~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -115,7 +133,7 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = Rx.of(42).pipe(publishReplay());
~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -125,7 +143,15 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
const a = Rx.of(42).pipe(shareReplay());
~~~~~~~~~~~ [forbidden]
- `
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // namespace shareReplay with config ignored
+ import * as Rx from "rxjs";
+ const a = Rx.of(42).pipe(Rx.shareReplay({ refCount: true }));
+ ~~~~~~~~~~~ [forbidden]
+ `,
),
fromFixture(
stripIndent`
@@ -139,7 +165,7 @@ ruleTester({ types: false }).run("no-ignored-replay-buffer", rule, {
~~~~~~~~~~~~~ [forbidden]
}
}
- `
+ `,
),
],
});
diff --git a/tests/rules/no-ignored-subscribe.ts b/tests/rules/no-ignored-subscribe.test.ts
similarity index 81%
rename from tests/rules/no-ignored-subscribe.ts
rename to tests/rules/no-ignored-subscribe.test.ts
index 59777431..7aaaafc4 100644
--- a/tests/rules/no-ignored-subscribe.ts
+++ b/tests/rules/no-ignored-subscribe.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredSubscribeRule } from '../../src/rules/no-ignored-subscribe';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-subscribe");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-subscribe", rule, {
+ruleTester({ types: true }).run('no-ignored-subscribe', noIgnoredSubscribeRule, {
valid: [
{
code: stripIndent`
@@ -68,7 +63,7 @@ ruleTester({ types: true }).run("no-ignored-subscribe", rule, {
const observable = of([1, 2]);
observable.subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -78,7 +73,7 @@ ruleTester({ types: true }).run("no-ignored-subscribe", rule, {
const subject = new Subject();
subject.subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -87,7 +82,7 @@ ruleTester({ types: true }).run("no-ignored-subscribe", rule, {
declare const subscribable: Subscribable;
subscribable.subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-ignored-subscription.ts b/tests/rules/no-ignored-subscription.test.ts
similarity index 74%
rename from tests/rules/no-ignored-subscription.ts
rename to tests/rules/no-ignored-subscription.test.ts
index 55276c5a..05d52e9d 100644
--- a/tests/rules/no-ignored-subscription.ts
+++ b/tests/rules/no-ignored-subscription.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredSubscriptionRule } from '../../src/rules/no-ignored-subscription';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-subscription");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-subscription", rule, {
+ruleTester({ types: true }).run('no-ignored-subscription', noIgnoredSubscriptionRule, {
valid: [
stripIndent`
// const and add
@@ -53,7 +48,7 @@ ruleTester({ types: true }).run("no-ignored-subscription", rule, {
import { of } from "rxjs";
of(42).subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -62,7 +57,7 @@ ruleTester({ types: true }).run("no-ignored-subscription", rule, {
const s = new Subject()
s.subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-ignored-takewhile-value.ts b/tests/rules/no-ignored-takewhile-value.test.ts
similarity index 90%
rename from tests/rules/no-ignored-takewhile-value.ts
rename to tests/rules/no-ignored-takewhile-value.test.ts
index 0062d6ca..8fb75376 100644
--- a/tests/rules/no-ignored-takewhile-value.ts
+++ b/tests/rules/no-ignored-takewhile-value.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIgnoredTakewhileValueRule } from '../../src/rules/no-ignored-takewhile-value';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-ignored-takewhile-value");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
+ruleTester({ types: true }).run('no-ignored-takewhile-value', noIgnoredTakewhileValueRule, {
valid: [
stripIndent`
// function
@@ -104,7 +99,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
fromFixture(
stripIndent`
@@ -120,7 +115,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
fromFixture(
stripIndent`
@@ -136,7 +131,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
fromFixture(
stripIndent`
@@ -152,7 +147,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
fromFixture(
stripIndent`
@@ -168,7 +163,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
fromFixture(
stripIndent`
@@ -184,7 +179,7 @@ ruleTester({ types: true }).run("no-ignored-takewhile-value", rule, {
).subscribe();
}
};
- `
+ `,
),
],
});
diff --git a/tests/rules/no-implicit-any-catch.ts b/tests/rules/no-implicit-any-catch.test.ts
similarity index 80%
rename from tests/rules/no-implicit-any-catch.ts
rename to tests/rules/no-implicit-any-catch.test.ts
index 5956e4f4..2e9cac6f 100644
--- a/tests/rules/no-implicit-any-catch.ts
+++ b/tests/rules/no-implicit-any-catch.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noImplicitAnyCatchRule } from '../../src/rules/no-implicit-any-catch';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-implicit-any-catch");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
+ruleTester({ types: true }).run('no-implicit-any-catch', noImplicitAnyCatchRule, {
valid: [
{
code: stripIndent`
@@ -64,7 +59,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
catchError((error: unknown) => console.error(error))
);
`,
- options: [{ allowExplicitAny: false }],
+ options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -76,7 +71,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
catchError(function (error: unknown) { console.error(error); })
);
`,
- options: [{ allowExplicitAny: false }],
+ options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -88,7 +83,6 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
catchError((error: any) => console.error(error))
);
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -100,7 +94,6 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
catchError(function (error: any) { console.error(error); })
);
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -115,7 +108,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
},
{
code: stripIndent`
- // subscribe; arrow; explicit any
+ // subscribe; arrow; explicit any; default option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
@@ -123,7 +116,6 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
(error: any) => console.error(error)
);
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -137,14 +129,13 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
},
{
code: stripIndent`
- // subscribe observer; arrow; explicit any
+ // subscribe observer; arrow; explicit any; default option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
error: (error: any) => console.error(error)
});
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -160,7 +151,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
},
{
code: stripIndent`
- // tap; arrow; explicit any
+ // tap; arrow; explicit any; default option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -169,7 +160,6 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
(error: any) => console.error(error)
));
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -184,7 +174,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
},
{
code: stripIndent`
- // tap observer; arrow; explicit any
+ // tap observer; arrow; explicit any; default option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -192,7 +182,6 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
error: (error: any) => console.error(error)
}));
`,
- options: [{ allowExplicitAny: true }],
},
{
code: stripIndent`
@@ -217,7 +206,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
throwError("Kaboom!").pipe(
catchError((error) => console.error(error))
- ~~~~~ [implicitAny]
+ ~~~~~ [implicitAny suggest]
);
`,
{
@@ -230,7 +219,21 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
catchError((error: unknown) => console.error(error))
);
`,
- }
+ suggestions: [
+ {
+ messageId: 'suggestExplicitUnknown',
+ output: stripIndent`
+ // arrow; implicit any
+ import { throwError } from "rxjs";
+ import { catchError } from "rxjs/operators";
+
+ throwError("Kaboom!").pipe(
+ catchError((error: unknown) => console.error(error))
+ );
+ `,
+ },
+ ],
+ },
),
fromFixture(
stripIndent`
@@ -255,7 +258,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// arrow; no parentheses; implicit any
import { throwError } from "rxjs";
@@ -267,7 +270,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -292,7 +295,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// non-arrow; implicit any
import { throwError } from "rxjs";
@@ -304,11 +307,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // arrow; explicit any; default option
+ // arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -318,8 +321,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
);
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // arrow; explicit any; default option
+ // arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -329,9 +333,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // arrow; explicit any; default option
+ // arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -341,11 +345,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // non-arrow; explicit any; default option
+ // non-arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -355,8 +359,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
);
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // non-arrow; explicit any; default option
+ // non-arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -366,9 +371,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // non-arrow; explicit any; default option
+ // non-arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -378,35 +383,25 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // arrow; explicit any; explicit option
+ // arrow; narrowed
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
throwError("Kaboom!").pipe(
- catchError((error: any) => console.error(error))
- ~~~~~~~~~~ [explicitAny suggest]
+ catchError((error: string) => console.error(error))
+ ~~~~~~~~~~~~~ [narrowed suggest]
);
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // arrow; explicit any; explicit option
- import { throwError } from "rxjs";
- import { catchError } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(
- catchError((error: unknown) => console.error(error))
- );
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // arrow; explicit any; explicit option
+ // arrow; narrowed
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -416,35 +411,25 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // non-arrow; explicit any; explicit option
+ // non-arrow; narrowed
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
throwError("Kaboom!").pipe(
- catchError(function (error: any) { console.error(error); })
- ~~~~~~~~~~ [explicitAny suggest]
+ catchError(function (error: string) { console.error(error); })
+ ~~~~~~~~~~~~~ [narrowed suggest]
);
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // non-arrow; explicit any; explicit option
- import { throwError } from "rxjs";
- import { catchError } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(
- catchError(function (error: unknown) { console.error(error); })
- );
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // non-arrow; explicit any; explicit option
+ // non-arrow; narrowed
import { throwError } from "rxjs";
import { catchError } from "rxjs/operators";
@@ -454,31 +439,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
- ),
- fromFixture(
- stripIndent`
- // arrow; narrowed
- import { throwError } from "rxjs";
- import { catchError } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(
- catchError((error: string) => console.error(error))
- ~~~~~~~~~~~~~ [narrowed]
- );
- `
- ),
- fromFixture(
- stripIndent`
- // non-arrow; narrowed
- import { throwError } from "rxjs";
- import { catchError } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(
- catchError(function (error: string) { console.error(error); })
- ~~~~~~~~~~~~~ [narrowed]
- );
- `
+ },
),
fromFixture(
stripIndent`
@@ -503,7 +464,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// subscribe; arrow; implicit any
import { throwError } from "rxjs";
@@ -515,7 +476,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -540,7 +501,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// subscribe; arrow; no parentheses; implicit any
import { throwError } from "rxjs";
@@ -552,11 +513,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // subscribe; arrow; explicit any; default option
+ // subscribe; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
@@ -566,8 +527,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
);
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // subscribe; arrow; explicit any; default option
+ // subscribe; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
@@ -577,9 +539,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // subscribe; arrow; explicit any; default option
+ // subscribe; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
@@ -589,35 +551,25 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // subscribe; arrow; explicit any; explicit option
+ // subscribe; arrow; narrowed
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
undefined,
- (error: any) => console.error(error)
- ~~~~~~~~~~ [explicitAny suggest]
+ (error: string) => console.error(error)
+ ~~~~~~~~~~~~~ [narrowed suggest]
);
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // subscribe; arrow; explicit any; explicit option
- import { throwError } from "rxjs";
-
- throwError("Kaboom!").subscribe(
- undefined,
- (error: unknown) => console.error(error)
- );
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // subscribe; arrow; explicit any; explicit option
+ // subscribe; arrow; narrowed
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe(
@@ -627,19 +579,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
- ),
- fromFixture(
- stripIndent`
- // subscribe; arrow; narrowed
- import { throwError } from "rxjs";
-
- throwError("Kaboom!").subscribe(
- undefined,
- (error: string) => console.error(error)
- ~~~~~~~~~~~~~ [narrowed]
- );
- `
+ },
),
fromFixture(
stripIndent`
@@ -662,7 +602,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// subscribe observer; arrow; implicit any
import { throwError } from "rxjs";
@@ -673,7 +613,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -696,7 +636,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// subscribe observer; arrow; no parentheses; implicit any
import { throwError } from "rxjs";
@@ -707,11 +647,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // subscribe observer; arrow; explicit any; default option
+ // subscribe observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
@@ -720,8 +660,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
});
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // subscribe observer; arrow; explicit any; default option
+ // subscribe observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
@@ -730,9 +671,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // subscribe observer; arrow; explicit any; default option
+ // subscribe observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
@@ -741,33 +682,24 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // subscribe observer; arrow; explicit any; explicit option
+ // subscribe observer; arrow; narrowed
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
- error: (error: any) => console.error(error)
- ~~~~~~~~~~ [explicitAny suggest]
+ error: (error: string) => console.error(error)
+ ~~~~~~~~~~~~~ [narrowed suggest]
});
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // subscribe observer; arrow; explicit any; explicit option
- import { throwError } from "rxjs";
-
- throwError("Kaboom!").subscribe({
- error: (error: unknown) => console.error(error)
- });
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // subscribe observer; arrow; explicit any; explicit option
+ // subscribe observer; arrow; narrowed
import { throwError } from "rxjs";
throwError("Kaboom!").subscribe({
@@ -776,18 +708,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
- ),
- fromFixture(
- stripIndent`
- // subscribe observer; arrow; narrowed
- import { throwError } from "rxjs";
-
- throwError("Kaboom!").subscribe({
- error: (error: string) => console.error(error)
- ~~~~~~~~~~~~~ [narrowed]
- });
- `
+ },
),
fromFixture(
stripIndent`
@@ -814,7 +735,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// tap; arrow; implicit any
import { throwError } from "rxjs";
@@ -827,7 +748,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -854,7 +775,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// tap; arrow; no parentheses; implicit any
import { throwError } from "rxjs";
@@ -867,11 +788,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // tap; arrow; explicit any; default option
+ // tap; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -882,8 +803,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
));
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // tap; arrow; explicit any; default option
+ // tap; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -894,9 +816,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // tap; arrow; explicit any; default option
+ // tap; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -907,37 +829,26 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // tap; arrow; explicit any; explicit option
+ // tap; arrow; narrowed
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
throwError("Kaboom!").pipe(tap(
undefined,
- (error: any) => console.error(error)
- ~~~~~~~~~~ [explicitAny suggest]
+ (error: string) => console.error(error)
+ ~~~~~~~~~~~~~ [narrowed suggest]
));
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // tap; arrow; explicit any; explicit option
- import { throwError } from "rxjs";
- import { tap } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(tap(
- undefined,
- (error: unknown) => console.error(error)
- ));
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // tap; arrow; explicit any; explicit option
+ // tap; arrow; narrowed
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -948,20 +859,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
- ),
- fromFixture(
- stripIndent`
- // tap; arrow; narrowed
- import { throwError } from "rxjs";
- import { tap } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(tap(
- undefined,
- (error: string) => console.error(error)
- ~~~~~~~~~~~~~ [narrowed]
- ));
- `
+ },
),
fromFixture(
stripIndent`
@@ -986,7 +884,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// tap observer; arrow; implicit any
import { throwError } from "rxjs";
@@ -998,7 +896,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -1023,7 +921,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
// tap observer; arrow; no parentheses; implicit any
import { throwError } from "rxjs";
@@ -1035,11 +933,11 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // tap observer; arrow; explicit any; default option
+ // tap observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -1049,8 +947,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
}));
`,
{
+ options: [{ allowExplicitAny: false }],
output: stripIndent`
- // tap observer; arrow; explicit any; default option
+ // tap observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -1060,9 +959,9 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // tap observer; arrow; explicit any; default option
+ // tap observer; arrow; explicit any; explicit option
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -1072,35 +971,25 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
- // tap observer; arrow; explicit any; explicit option
+ // tap observer; arrow; narrowed
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
throwError("Kaboom!").pipe(tap({
- error: (error: any) => console.error(error)
- ~~~~~~~~~~ [explicitAny suggest]
+ error: (error: string) => console.error(error)
+ ~~~~~~~~~~~~~ [narrowed suggest]
}));
`,
{
- options: [{ allowExplicitAny: false }],
- output: stripIndent`
- // tap observer; arrow; explicit any; explicit option
- import { throwError } from "rxjs";
- import { tap } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(tap({
- error: (error: unknown) => console.error(error)
- }));
- `,
suggestions: [
{
- messageId: "suggestExplicitUnknown",
+ messageId: 'suggestExplicitUnknown',
output: stripIndent`
- // tap observer; arrow; explicit any; explicit option
+ // tap observer; arrow; narrowed
import { throwError } from "rxjs";
import { tap } from "rxjs/operators";
@@ -1110,19 +999,7 @@ ruleTester({ types: true }).run("no-implicit-any-catch", rule, {
`,
},
],
- }
- ),
- fromFixture(
- stripIndent`
- // tap observer; arrow; narrowed
- import { throwError } from "rxjs";
- import { tap } from "rxjs/operators";
-
- throwError("Kaboom!").pipe(tap({
- error: (error: string) => console.error(error)
- ~~~~~~~~~~~~~ [narrowed]
- }));
- `
+ },
),
],
});
diff --git a/tests/rules/no-index.ts b/tests/rules/no-index.test.ts
similarity index 80%
rename from tests/rules/no-index.ts
rename to tests/rules/no-index.test.ts
index 4a090d5e..2de748a3 100644
--- a/tests/rules/no-index.ts
+++ b/tests/rules/no-index.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noIndexRule } from '../../src/rules/no-index';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-index");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-index", rule, {
+ruleTester({ types: false }).run('no-index', noIndexRule, {
valid: [
stripIndent`
// no index double quote
@@ -37,7 +32,7 @@ ruleTester({ types: false }).run("no-index", rule, {
~~~~~~~~~~~~~~~~~~~~ [forbidden]
import { WebSocketSubject } from "rxjs/webSocket/index";
~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -50,7 +45,7 @@ ruleTester({ types: false }).run("no-index", rule, {
~~~~~~~~~~~~~~~~~~~~ [forbidden]
import { WebSocketSubject } from 'rxjs/webSocket/index';
~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-internal.ts b/tests/rules/no-internal.test.ts
similarity index 88%
rename from tests/rules/no-internal.ts
rename to tests/rules/no-internal.test.ts
index 956f3e4a..ece3681e 100644
--- a/tests/rules/no-internal.ts
+++ b/tests/rules/no-internal.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noInternalRule } from '../../src/rules/no-internal';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-internal");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-internal", rule, {
+ruleTester({ types: false }).run('no-internal', noInternalRule, {
valid: [
stripIndent`
// no internal double quote
@@ -38,7 +33,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal double quote
import { concat } from "rxjs";
@@ -46,7 +41,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
},
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal double quote
import { concat } from "rxjs/internal/observable/concat";
@@ -54,7 +49,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -72,7 +67,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal single quote
import { concat } from 'rxjs';
@@ -80,7 +75,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
},
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal single quote
import { concat } from 'rxjs/internal/observable/concat';
@@ -88,7 +83,7 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -103,14 +98,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal ajax
import { ajax } from "rxjs";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -125,14 +120,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal fetch
import { fromFetch } from "rxjs/fetch";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -147,14 +142,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal webSocket
import { webSocket } from "rxjs/webSocket";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -169,14 +164,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal observable
import { concat } from "rxjs";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -191,14 +186,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal operator
import { map } from "rxjs/operators";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -213,14 +208,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal scheduled
import { scheduled } from "rxjs";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -235,14 +230,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal scheduler
import { asap } from "rxjs";
`,
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -257,14 +252,14 @@ ruleTester({ types: false }).run("no-internal", rule, {
`,
suggestions: [
{
- messageId: "suggest",
+ messageId: 'suggest',
output: stripIndent`
// internal testing
import { TestScheduler } from "rxjs/testing";
`,
},
],
- }
+ },
),
],
});
diff --git a/tests/rules/no-misused-observables.test.ts b/tests/rules/no-misused-observables.test.ts
new file mode 100644
index 00000000..32ac0221
--- /dev/null
+++ b/tests/rules/no-misused-observables.test.ts
@@ -0,0 +1,851 @@
+import { stripIndent } from 'common-tags';
+import { noMisusedObservablesRule } from '../../src/rules/no-misused-observables';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRule, {
+ valid: [
+ {
+ code: stripIndent`
+ // all checks disabled
+ import { of } from "rxjs";
+
+ [1, 2, 3].forEach(i => of(i));
+
+ const source = of(42);
+ const foo = { ...source };
+ `,
+ options: [{ checksVoidReturn: false, checksSpreads: false }],
+ },
+ // #region valid; void return argument
+ {
+ code: stripIndent`
+ // void return argument; explicitly allowed
+ import { Observable, of } from "rxjs";
+
+ [1, 2, 3].forEach((i): Observable => { return of(i); });
+ [1, 2, 3].forEach(i => of(i));
+
+ class Foo {
+ constructor(x: () => void) {}
+ }
+ new Foo(() => of(42));
+ `,
+ options: [{ checksVoidReturn: { arguments: false } }],
+ },
+ stripIndent`
+ // void return argument; unrelated
+ [1, 2, 3].forEach(i => i);
+ [1, 2, 3].forEach(i => { return i; });
+
+ class Foo {
+ constructor(x: () => void, y: number) {}
+ }
+ new Foo(() => 42, 0);
+ new Foo;
+ `,
+ stripIndent`
+ // couldReturnType is bugged for block body implicit return types (#57)
+ import { of } from "rxjs";
+
+ [1, 2, 3].forEach(i => { return of(i); });
+ `,
+ // #endregion valid; void return argument
+ // #region valid; void return attribute
+ {
+ code: stripIndent`
+ // void return attribute; explicitly allowed
+ import { Observable, of } from "rxjs";
+ import React, { FC } from "react";
+
+ const Component: FC<{ foo: () => void }> = () => ;
+ const App = () => {
+ return (
+ of(42)} />
+ );
+ };
+ `,
+ options: [{ checksVoidReturn: { attributes: false } }],
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ },
+ {
+ code: stripIndent`
+ // void return attribute; unrelated
+ import React, { FC } from "react";
+
+ const Component: FC<{ foo: () => void, bar: boolean }> = () => ;
+ const App = () => {
+ return (
+ 42} bar />
+ );
+ };
+ `,
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ },
+ // #endregion valid; void return attribute
+ // #region valid; void return inherited method
+ {
+ code: stripIndent`
+ // void return inherited method; explicitly allowed
+ import { Observable, of } from "rxjs";
+
+ class Foo {
+ foo(): void {}
+ }
+
+ class Bar extends Foo {
+ foo(): Observable { return of(42); }
+ }
+
+ const Baz = class extends Foo {
+ foo(): Observable { return of(42); }
+ }
+
+ interface Qux extends Foo {
+ foo(): Observable;
+ }
+ `,
+ options: [{ checksVoidReturn: { inheritedMethods: false } }],
+ },
+ stripIndent`
+ // void return inherited method; not void
+ import { Observable, of } from "rxjs";
+
+ class Foo {
+ foo(): Observable { return of(42); }
+ s(): void {}
+ }
+
+ class Bar extends Foo {
+ foo(): Observable { return of(43); }
+ static s(): Observable { return of(43); }
+ }
+
+ const Baz = class extends Foo {
+ foo(): Observable { return of(44); }
+ }
+
+ interface Qux extends Foo {
+ foo(): Observable<45>;
+ }
+ `,
+ stripIndent`
+ // void return inherited method; unrelated
+ class Foo {
+ foo(): void {}
+ }
+
+ class Bar extends Foo {
+ foo(): number { return 42; }
+ }
+ `,
+ // #endregion valid; void return inherited method
+ // #region valid; void return property
+ {
+ code: stripIndent`
+ // void return property; explicitly allowed
+ import { Observable, of } from "rxjs";
+
+ type Foo = { a: () => void, b: () => void, c: () => void };
+ const b: () => Observable = () => of(42);
+ const foo: Foo = {
+ a: (): Observable => of(42),
+ b,
+ c(): Observable { return of(42); },
+ };
+ `,
+ options: [{ checksVoidReturn: { properties: false } }],
+ },
+ stripIndent`
+ // void return property; not void
+ import { Observable, of } from "rxjs";
+
+ type Foo = { a: () => Observable, b: () => Observable, c: () => Observable };
+ const b: () => Observable = () => of(42);
+ const foo: Foo = {
+ a: () => of(42),
+ b,
+ c(): Observable { return of(42); },
+ d(): Observable { return of(42); },
+ };
+ `,
+ stripIndent`
+ // void return property; unrelated
+ import { Observable, of } from "rxjs";
+
+ type Foo = { a: () => void, b: () => void, c: () => void };
+ const b: () => number = () => 42;
+ const foo: Foo = {
+ a: () => 42,
+ b,
+ ['c'](): number { return 42; },
+ };
+ const bar = {
+ a(): Observable { return of(42); },
+ }
+ `,
+ stripIndent`
+ // computed property name for method declaration is not supported
+ import { Observable, of } from "rxjs";
+
+ type Foo = { a: () => void };
+ const foo: Foo = {
+ ['a'](): Observable { return of(42); },
+ };
+ `,
+ stripIndent`
+ // couldReturnType is bugged for variables (#66)
+ import { Observable, of } from "rxjs";
+
+ type Foo = { bar: () => void };
+ const bar: () => Observable = () => of(42);
+ const foo: Foo = {
+ bar,
+ };
+ `,
+ // #endregion valid; void return property
+ // #region valid; void return return value
+ {
+ code: stripIndent`
+ // void return return value; explicitly allowed
+ import { Observable, of } from "rxjs";
+
+ function foo(): () => void {
+ return (): Observable => of(42);
+ }
+ `,
+ options: [{ checksVoidReturn: { returns: false } }],
+ },
+ stripIndent`
+ // void return return value; not void
+ import { Observable, of } from "rxjs";
+
+ function foo(): () => Observable {
+ return (): Observable => of(42);
+ }
+ `,
+ stripIndent`
+ // void return return value; unrelated
+ function foo(): () => number {
+ return (): number => 42;
+ }
+ function bar(): () => void {
+ return (): number => 42;
+ }
+ function baz(): () => void {
+ return (): void => { return; };
+ }
+ `,
+ // #endregion valid; void return return value
+ // #region valid; void return variable
+ {
+ code: stripIndent`
+ // void return variable; explicitly allowed
+ import { Observable, of } from "rxjs";
+
+ let foo: () => void;
+ foo = (): Observable => of(42);
+ const bar: () => void = (): Observable => of(42);
+ `,
+ options: [{ checksVoidReturn: { variables: false } }],
+ },
+ stripIndent`
+ // void return variable; not void
+ import { Observable, of } from "rxjs";
+
+ let foo: () => Observable;
+ foo = () => of(42);
+ `,
+ stripIndent`
+ // void return variable; unrelated
+ let foo: () => void;
+ foo = (): number => 42;
+ `,
+ // #endregion valid; void return variable
+ // #region valid; spread
+ {
+ code: stripIndent`
+ // spread; explicitly allowed
+ import { of } from "rxjs";
+
+ const source = of(42);
+ const foo = { ...source };
+ `,
+ options: [{ checksSpreads: false }],
+ },
+ stripIndent`
+ // spread; unrelated
+ const foo = { bar: 42 };
+ const baz = { ...foo };
+ `,
+ // #endregion valid; spread
+ ],
+ invalid: [
+ // #region invalid; void return argument
+ fromFixture(
+ stripIndent`
+ // void return argument; block body
+ import { Observable, of } from "rxjs";
+
+ [1, 2, 3].forEach((i): Observable => { return of(i); });
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnArgument]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return argument; inline body
+ import { of } from "rxjs";
+
+ [1, 2, 3].forEach(i => of(i));
+ ~~~~~~~~~~ [forbiddenVoidReturnArgument]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return argument; block body; union return
+ import { Observable, of } from "rxjs";
+
+ [1, 2, 3].forEach((i): Observable | number => { if (i > 1) { return of(i); } else { return i; } });
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnArgument]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return argument; inline body; union return
+ import { of } from "rxjs";
+
+ [1, 2, 3].forEach(i => i > 1 ? of(i) : i);
+ ~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnArgument]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return argument; constructor
+ import { of } from "rxjs";
+
+ class Foo {
+ constructor(x: () => void) {}
+ }
+ new Foo(() => of(42));
+ ~~~~~~~~~~~~ [forbiddenVoidReturnArgument]
+ `,
+ ),
+ // #endregion invalid; void return argument
+ // #region invalid; void return attribute
+ fromFixture(
+ stripIndent`
+ // void return attribute; block body
+ import { Observable, of } from "rxjs";
+ import React, { FC } from "react";
+
+ const Component: FC<{ foo: () => void }> = () => ;
+ const App = () => {
+ return (
+ => { return of(42); }} />
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnAttribute]
+ );
+ };
+ `,
+ {
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // void return attribute; inline body
+ import { Observable, of } from "rxjs";
+ import React, { FC } from "react";
+
+ const Component: FC<{ foo: () => void }> = () => ;
+ const App = () => {
+ return (
+ of(42)} />
+ ~~~~~~~~~~~~~~ [forbiddenVoidReturnAttribute]
+ );
+ };
+ `,
+ {
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ },
+ ),
+ // #endregion invalid; void return attribute
+ // #region invalid; void return inherited method
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; extends
+ import { Observable, of } from "rxjs";
+
+ class Foo {
+ foo(): void {}
+ }
+
+ class Bar extends Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; abstract extends
+ import { Observable } from "rxjs";
+
+ class Foo {
+ foo(): void {}
+ }
+
+ abstract class Bar extends Foo {
+ abstract foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; extends abstract
+ import { Observable, of } from "rxjs";
+
+ abstract class Foo {
+ abstract foo(): void;
+ }
+
+ class Bar extends Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; abstract extends abstract
+ import { Observable } from "rxjs";
+
+ abstract class Foo {
+ abstract foo(): void;
+ }
+
+ abstract class Bar extends Foo {
+ abstract foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; implements
+ import { Observable, of } from "rxjs";
+
+ interface Foo {
+ foo(): void;
+ }
+
+ class Bar implements Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; abstract implements
+ import { Observable } from "rxjs";
+
+ interface Foo {
+ foo(): void;
+ }
+
+ abstract class Bar implements Foo {
+ abstract foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; implements type intersection
+ import { Observable, of } from "rxjs";
+
+ type Foo = { foo(): void } & { bar(): void };
+
+ class Bar implements Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ bar(): void {}
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; extends and implements
+ import { Observable, of } from "rxjs";
+
+ interface Foo {
+ foo(): Observable;
+ }
+
+ interface Bar {
+ foo(): void;
+ }
+
+ class Baz {
+ foo(): void {}
+ }
+
+ class Qux extends Baz implements Foo, Bar {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Baz" }]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Bar" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class declaration; extends class expression
+ import { Observable, of } from "rxjs";
+
+ const Foo = class {
+ foo(): void {}
+ }
+
+ class Bar extends Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class expression; extends
+ import { Observable, of } from "rxjs";
+
+ const Foo = class {
+ foo(): void {}
+ }
+
+ const Bar = class extends Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; class expression; implements
+ import { Observable, of } from "rxjs";
+
+ interface Foo {
+ foo(): void;
+ }
+
+ const Bar = class implements Foo {
+ foo(): Observable { return of(42); }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends class
+ import { Observable } from "rxjs";
+
+ class Foo {
+ foo(): void {}
+ }
+
+ interface Bar extends Foo {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends abstract
+ import { Observable } from "rxjs";
+
+ abstract class Foo {
+ abstract foo(): void;
+ }
+
+ interface Bar extends Foo {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends interface
+ import { Observable } from "rxjs";
+
+ interface Foo {
+ foo(): void;
+ }
+
+ interface Bar extends Foo {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends conditional type
+ import { Observable } from "rxjs";
+
+ type Foo = IsRx extends true
+ ? { foo(): Observable }
+ : { foo(): void };
+
+ interface Bar extends Foo {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "{ foo(): void; }" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends multiple
+ import { Observable } from "rxjs";
+
+ interface Foo {
+ foo(): void;
+ }
+
+ interface Bar {
+ foo(): void;
+ }
+
+ interface Baz extends Foo, Bar {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Bar" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends multiple classes
+ import { Observable } from "rxjs";
+
+ class Foo {
+ foo(): void {}
+ }
+
+ class Bar {
+ foo(): void {}
+ }
+
+ interface Baz extends Foo, Bar {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Bar" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends typeof class
+ import { Observable } from "rxjs";
+
+ const Foo = class {
+ foo(): void {}
+ }
+
+ type Bar = typeof Foo;
+
+ interface Baz extends Bar {
+ foo(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "typeof Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends function, index, constructor
+ import { Observable } from "rxjs";
+
+ interface Foo {
+ (): void;
+ (arg: string): void;
+ new (): void;
+ [key: string]: () => void;
+ [key: number]: () => void;
+ myMethod(): void;
+ }
+
+ interface Bar extends Foo {
+ (): Observable;
+ (arg: string): Observable;
+ new (): Observable;
+ [key: string]: () => Observable;
+ [key: number]: () => Observable;
+ myMethod(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return inherited method; interface; extends multiple function, index, constructor
+ import { Observable } from "rxjs";
+
+ interface Foo {
+ (): void;
+ (arg: string): void;
+ }
+
+ interface Bar {
+ [key: string]: () => void;
+ [key: number]: () => void;
+ }
+
+ interface Baz {
+ new (): void;
+ new (arg: string): void;
+ }
+
+ interface Qux {
+ doSyncThing(): void;
+ doOtherSyncThing(): void;
+ syncMethodProperty: () => void;
+ }
+
+ interface Quux extends Foo, Bar, Baz, Qux {
+ (): void;
+ (arg: string): Observable;
+ new (): void;
+ new (arg: string): void;
+ [key: string]: () => Observable;
+ [key: number]: () => void;
+ doSyncThing(): Observable;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Qux" }]
+ doRxThing(): Observable;
+ syncMethodProperty: () => Observable;
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Qux" }]
+ // TODO(#66): couldReturnType doesn't work for properties.
+ }
+ `,
+ ),
+ // #endregion invalid; void return inherited method
+ // #region invalid; void return property
+ fromFixture(
+ stripIndent`
+ // void return property; arrow function
+ import { of } from "rxjs";
+
+ type Foo = { bar: () => void };
+ const foo: Foo = {
+ bar: () => of(42),
+ ~~~~~~~~~~~~ [forbiddenVoidReturnProperty]
+ };
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return property; function
+ import { Observable, of } from "rxjs";
+
+ type Foo = { bar: () => void };
+ const foo: Foo = {
+ bar(): Observable { return of(42); },
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnProperty]
+ };
+ `,
+ ),
+ // #endregion invalid; void return property
+ // #region invalid; void return return value
+ fromFixture(
+ stripIndent`
+ // void return return value; arrow function
+ import { Observable, of } from "rxjs";
+
+ function foo(): () => void {
+ return (): Observable => of(42);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnReturnValue]
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return return value; function
+ import { Observable, of } from "rxjs";
+
+ function foo(): () => void {
+ return function(): Observable { return of(42); };
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnReturnValue]
+ }
+ `,
+ ),
+ // #endregion invalid; void return return value
+ // #region invalid; void return variable
+ fromFixture(
+ stripIndent`
+ // void return variable; reassign
+ import { of } from "rxjs";
+
+ let foo: () => void;
+ foo = () => of(42);
+ ~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return variable; const
+ import { of } from "rxjs";
+
+ const foo: () => void = () => of(42);
+ ~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
+ const bar = () => of(42), baz: () => void = () => of(42);
+ ~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return variable; nested
+ import { of } from "rxjs";
+
+ const foo: {
+ bar?: () => void;
+ } = {};
+ foo.bar = () => of(42);
+ ~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // void return variable; Record
+ import { of } from "rxjs";
+
+ const foo: Record void> = {};
+ foo.bar = () => of(42);
+ ~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
+ `,
+ ),
+ // #endregion invalid; void return variable
+ // #region invalid; spread
+ fromFixture(
+ stripIndent`
+ // spread variable
+ import { of } from "rxjs";
+
+ const source = of(42);
+ const foo = { ...source };
+ ~~~~~~ [forbiddenSpread]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // spread call function
+ import { of } from "rxjs";
+
+ function source() {
+ return of(42);
+ }
+ const foo = { ...source() };
+ ~~~~~~~~ [forbiddenSpread]
+ `,
+ ),
+ // #endregion invalid; spread
+ ],
+});
diff --git a/tests/rules/no-nested-subscribe.ts b/tests/rules/no-nested-subscribe.test.ts
similarity index 89%
rename from tests/rules/no-nested-subscribe.ts
rename to tests/rules/no-nested-subscribe.test.ts
index d191da53..13c72518 100644
--- a/tests/rules/no-nested-subscribe.ts
+++ b/tests/rules/no-nested-subscribe.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noNestedSubscribeRule } from '../../src/rules/no-nested-subscribe';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-nested-subscribe");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-nested-subscribe", rule, {
+ruleTester({ types: true }).run('no-nested-subscribe', noNestedSubscribeRule, {
valid: [
stripIndent`
// not nested in next argument
@@ -77,7 +72,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
value => of("bar").subscribe()
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -87,7 +82,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
next: value => of("bar").subscribe()
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -97,7 +92,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
next(value) { of("bar").subscribe(); }
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -108,7 +103,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
error => of("bar").subscribe()
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -118,7 +113,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
error: error => of("bar").subscribe()
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -128,7 +123,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
error(error) { of("bar").subscribe(); }
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -140,7 +135,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
() => of("bar").subscribe()
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -150,7 +145,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
complete: () => of("bar").subscribe()
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -160,7 +155,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
complete() { of("bar").subscribe(); }
~~~~~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -171,7 +166,7 @@ ruleTester({ types: true }).run("no-nested-subscribe", rule, {
() => subscribable.subscribe()
~~~~~~~~~ [forbidden]
);
- `
+ `,
),
],
});
diff --git a/tests/rules/no-redundant-notify.ts b/tests/rules/no-redundant-notify.test.ts
similarity index 91%
rename from tests/rules/no-redundant-notify.ts
rename to tests/rules/no-redundant-notify.test.ts
index ebcf7950..ce124a17 100644
--- a/tests/rules/no-redundant-notify.ts
+++ b/tests/rules/no-redundant-notify.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noRedundantNotifyRule } from '../../src/rules/no-redundant-notify';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-redundant-notify");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-redundant-notify", rule, {
+ruleTester({ types: true }).run('no-redundant-notify', noRedundantNotifyRule, {
valid: [
stripIndent`
// observable next + complete
@@ -87,7 +82,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.next(42);
~~~~ [forbidden]
})
- `
+ `,
),
fromFixture(
stripIndent`
@@ -98,7 +93,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.complete();
~~~~~~~~ [forbidden]
})
- `
+ `,
),
fromFixture(
stripIndent`
@@ -109,7 +104,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.error(new Error("Kaboom!"));
~~~~~ [forbidden]
})
- `
+ `,
),
fromFixture(
stripIndent`
@@ -120,7 +115,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.next(42);
~~~~ [forbidden]
})
- `
+ `,
),
fromFixture(
stripIndent`
@@ -131,7 +126,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.complete();
~~~~~~~~ [forbidden]
})
- `
+ `,
),
fromFixture(
stripIndent`
@@ -142,7 +137,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
observer.error(new Error("Kaboom!"));
~~~~~ [forbidden]
});
- `
+ `,
),
fromFixture(
stripIndent`
@@ -152,7 +147,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.complete();
subject.next(42);
~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -162,7 +157,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.complete();
subject.complete();
~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -172,7 +167,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.complete();
subject.error(new Error("Kaboom!"));
~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -182,7 +177,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.error(new Error("Kaboom!"));
subject.next(42);
~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -192,7 +187,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.error(new Error("Kaboom!"));
subject.complete();
~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -202,7 +197,7 @@ ruleTester({ types: true }).run("no-redundant-notify", rule, {
subject.error(new Error("Kaboom!"));
subject.error(new Error("Kaboom!"));
~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-sharereplay.ts b/tests/rules/no-sharereplay.test.ts
similarity index 74%
rename from tests/rules/no-sharereplay.ts
rename to tests/rules/no-sharereplay.test.ts
index 1d99867d..0688df70 100644
--- a/tests/rules/no-sharereplay.ts
+++ b/tests/rules/no-sharereplay.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noSharereplayRule } from '../../src/rules/no-sharereplay';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-sharereplay");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-sharereplay", rule, {
+ruleTester({ types: false }).run('no-sharereplay', noSharereplayRule, {
valid: [
{
code: stripIndent`
@@ -34,7 +29,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
~~~~~~~~~~~ [forbidden]
);
`,
- { options: [{ allowConfig: false }] }
+ { options: [{ allowConfig: false }] },
),
fromFixture(
stripIndent`
@@ -44,7 +39,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
~~~~~~~~~~~ [forbiddenWithoutConfig]
);
`,
- { options: [{ allowConfig: true }] }
+ { options: [{ allowConfig: true }] },
),
fromFixture(
stripIndent`
@@ -53,7 +48,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
shareReplay(1)
~~~~~~~~~~~ [forbiddenWithoutConfig]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -62,7 +57,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
shareReplay(1, 100)
~~~~~~~~~~~ [forbiddenWithoutConfig]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -71,7 +66,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
shareReplay(1, 100, asapScheduler)
~~~~~~~~~~~ [forbiddenWithoutConfig]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -81,7 +76,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
~~~~~~~~~~~ [forbidden]
);
`,
- { options: [{ allowConfig: false }] }
+ { options: [{ allowConfig: false }] },
),
fromFixture(
stripIndent`
@@ -91,7 +86,7 @@ ruleTester({ types: false }).run("no-sharereplay", rule, {
~~~~~~~~~~~ [forbidden]
);
`,
- { options: [{ allowConfig: false }] }
+ { options: [{ allowConfig: false }] },
),
],
});
diff --git a/tests/rules/no-subclass.ts b/tests/rules/no-subclass.test.ts
similarity index 85%
rename from tests/rules/no-subclass.ts
rename to tests/rules/no-subclass.test.ts
index 8f75e0aa..afd3e036 100644
--- a/tests/rules/no-subclass.ts
+++ b/tests/rules/no-subclass.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noSubclassRule } from '../../src/rules/no-subclass';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-subclass");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-subclass", rule, {
+ruleTester({ types: true }).run('no-subclass', noSubclassRule, {
valid: [
stripIndent`
// non-RxJS Observable
@@ -25,7 +20,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~~~~ [forbidden]
class StringObservable extends Observable {}
~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -35,7 +30,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~ [forbidden]
class StringSubject extends Subject {}
~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -45,7 +40,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~~~~ [forbidden]
class StringSubscriber extends Subscriber {}
~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -55,7 +50,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~~~~~~ [forbidden]
class StringAsyncSubject extends AsyncSubject {}
~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -65,7 +60,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~~~~~~~~~ [forbidden]
class StringBehaviorSubject extends BehaviorSubject {}
~~~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -75,7 +70,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
~~~~~~~~~~~~~ [forbidden]
class StringReplaySubject extends ReplaySubject {}
~~~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -83,7 +78,7 @@ ruleTester({ types: true }).run("no-subclass", rule, {
import { Scheduler } from "rxjs/internal/Scheduler";
class AnotherScheduler extends Scheduler {}
~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-subject-unsubscribe.ts b/tests/rules/no-subject-unsubscribe.test.ts
similarity index 75%
rename from tests/rules/no-subject-unsubscribe.ts
rename to tests/rules/no-subject-unsubscribe.test.ts
index 73e23fc9..d7f8ce9c 100644
--- a/tests/rules/no-subject-unsubscribe.ts
+++ b/tests/rules/no-subject-unsubscribe.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noSubjectUnsubscribeRule } from '../../src/rules/no-subject-unsubscribe';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-subject-unsubscribe");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-subject-unsubscribe", rule, {
+ruleTester({ types: true }).run('no-subject-unsubscribe', noSubjectUnsubscribeRule, {
valid: [
stripIndent`
// unsubscribe Subject subscription
@@ -33,7 +28,7 @@ ruleTester({ types: true }).run("no-subject-unsubscribe", rule, {
const b = new Subject();
b.unsubscribe();
~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -42,7 +37,7 @@ ruleTester({ types: true }).run("no-subject-unsubscribe", rule, {
const b = new AsyncSubject();
b.unsubscribe();
~~~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -52,7 +47,7 @@ ruleTester({ types: true }).run("no-subject-unsubscribe", rule, {
const c = new Subject();
csub.add(c);
~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -62,7 +57,7 @@ ruleTester({ types: true }).run("no-subject-unsubscribe", rule, {
const c = new AsyncSubject();
csub.add(c);
~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-subject-value.ts b/tests/rules/no-subject-value.test.ts
similarity index 61%
rename from tests/rules/no-subject-value.ts
rename to tests/rules/no-subject-value.test.ts
index 56315b5c..91df4ce2 100644
--- a/tests/rules/no-subject-value.ts
+++ b/tests/rules/no-subject-value.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noSubjectValueRule } from '../../src/rules/no-subject-value';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-subject-value");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-subject-value", rule, {
+ruleTester({ types: true }).run('no-subject-value', noSubjectValueRule, {
valid: [
stripIndent`
// no value
@@ -24,7 +19,7 @@ ruleTester({ types: true }).run("no-subject-value", rule, {
const subject = new BehaviorSubject(1);
console.log(subject.value);
~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -33,7 +28,7 @@ ruleTester({ types: true }).run("no-subject-value", rule, {
const subject = new BehaviorSubject(1);
console.log(subject.getValue());
~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-subscribe-handlers.ts b/tests/rules/no-subscribe-handlers.test.ts
similarity index 82%
rename from tests/rules/no-subscribe-handlers.ts
rename to tests/rules/no-subscribe-handlers.test.ts
index 62f66475..31d85f57 100644
--- a/tests/rules/no-subscribe-handlers.ts
+++ b/tests/rules/no-subscribe-handlers.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noSubscribeHandlersRule } from '../../src/rules/no-subscribe-handlers';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-subscribe-handlers");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
+ruleTester({ types: true }).run('no-subscribe-handlers', noSubscribeHandlersRule, {
valid: [
{
code: stripIndent`
@@ -61,7 +56,7 @@ ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
const observable = of([1, 2]);
observable.subscribe(value => console.log(value));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -71,7 +66,7 @@ ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
const subject = new Subject();
subject.subscribe(value => console.log(value));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -85,7 +80,7 @@ ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
const observable = of([1, 2]);
observable.subscribe(log);
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -93,7 +88,7 @@ ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
declare const subscribable: Subscribable;
subscribable.subscribe((value) => console.log(value));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -103,7 +98,7 @@ ruleTester({ types: true }).run("no-subscribe-handlers", rule, {
~~~~~~~~~ [forbidden]
next: (value) => console.log(value)
});
- `
+ `,
),
],
});
diff --git a/tests/rules/no-subscribe-in-pipe.test.ts b/tests/rules/no-subscribe-in-pipe.test.ts
new file mode 100644
index 00000000..78a126ae
--- /dev/null
+++ b/tests/rules/no-subscribe-in-pipe.test.ts
@@ -0,0 +1,206 @@
+import { stripIndent } from 'common-tags';
+import { noSubscribeInPipeRule } from '../../src/rules/no-subscribe-in-pipe';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-subscribe-in-pipe', noSubscribeInPipeRule, {
+ valid: [
+ stripIndent`
+ // subscribe outside of pipe
+ import { of } from "rxjs";
+ of(47).subscribe(value => {
+ console.log(value);
+ });
+ `,
+ stripIndent`
+ // pipe without subscribe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => x * 2)
+ ).subscribe(value => {
+ console.log(value);
+ });
+ `,
+ stripIndent`
+ // nested pipes without subscribe
+ import { of } from "rxjs";
+ import { map, mergeMap } from "rxjs/operators";
+ of(47).pipe(
+ mergeMap(x => of(x).pipe(
+ map(y => y * 2)
+ ))
+ ).subscribe(value => {
+ console.log(value);
+ });
+ `,
+ stripIndent`
+ // subscribe in a function outside pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ const logValue = (value) => of(value).subscribe(console.log);
+ of(47).pipe(
+ map(x => x * 2)
+ ).subscribe(logValue);
+ `,
+ stripIndent`
+ // subscribe method on a non-Observable object inside pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ const customObject = { subscribe: () => {} };
+ of(47).pipe(
+ map(x => {
+ customObject.subscribe();
+ return x * 2;
+ })
+ ).subscribe();
+ `,
+ stripIndent`
+ // subscribe as a variable name inside pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => {
+ const subscribe = 5;
+ return x * subscribe;
+ })
+ ).subscribe();
+ `,
+ stripIndent`
+ // subscribe in a comment inside pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => {
+ // of(x).subscribe(console.log);
+ return x * 2;
+ })
+ ).subscribe();
+ `,
+ stripIndent`
+ // subscribe as a string inside pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => {
+ console.log("subscribe");
+ return x * 2;
+ })
+ ).subscribe();
+ `,
+ stripIndent`
+ // subscribe inside of an Observable constructor
+ import { Observable, of } from "rxjs";
+
+ new Observable(subscriber => {
+ of(42).subscribe(subscriber);
+ }).subscribe();
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // subscribe inside map operator
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => {
+ of(x).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ return x * 2;
+ })
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe inside mergeMap operator
+ import { of } from "rxjs";
+ import { mergeMap } from "rxjs/operators";
+ of(47).pipe(
+ mergeMap(x => of(x).pipe(
+ map(y => {
+ of(y).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ return y * 2;
+ })
+ ))
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe inside tap operator
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+ of(47).pipe(
+ tap(x => {
+ of(x).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ })
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe inside switchMap operator
+ import { of } from "rxjs";
+ import { switchMap } from "rxjs/operators";
+ of(47).pipe(
+ switchMap(x => {
+ of(x).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ return of(x * 2);
+ })
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe inside nested pipes
+ import { of } from "rxjs";
+ import { map, mergeMap } from "rxjs/operators";
+ of(47).pipe(
+ mergeMap(x => of(x).pipe(
+ map(y => {
+ of(y).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ return y * 2;
+ })
+ ))
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe inside a deeply nested function in pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => {
+ const nestedFunc = () => {
+ const deeplyNested = () => {
+ of(x).subscribe(console.log);
+ ~~~~~~~~~ [forbidden]
+ };
+ deeplyNested();
+ };
+ nestedFunc();
+ return x * 2;
+ })
+ ).subscribe();
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // subscribe in a ternary operator in pipe
+ import { of } from "rxjs";
+ import { map } from "rxjs/operators";
+ of(47).pipe(
+ map(x => x > 50 ? x : of(x).subscribe(console.log))
+ ~~~~~~~~~ [forbidden]
+ ).subscribe();
+ `,
+ ),
+ ],
+});
diff --git a/tests/rules/no-tap.ts b/tests/rules/no-tap.test.ts
similarity index 75%
rename from tests/rules/no-tap.ts
rename to tests/rules/no-tap.test.ts
index f77248c5..db24dd18 100644
--- a/tests/rules/no-tap.ts
+++ b/tests/rules/no-tap.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noTapRule } from '../../src/rules/no-tap';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-tap");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: false }).run("no-tap", rule, {
+ruleTester({ types: false }).run('no-tap', noTapRule, {
valid: [
stripIndent`
// no tap
@@ -37,7 +32,7 @@ ruleTester({ types: false }).run("no-tap", rule, {
map(x => x * 2),
tap(value => console.log(value))
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -48,7 +43,7 @@ ruleTester({ types: false }).run("no-tap", rule, {
map(x => x * 2),
tap(value => console.log(value))
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -60,7 +55,7 @@ ruleTester({ types: false }).run("no-tap", rule, {
map(x => x * 2),
tapAlias(value => console.log(value))
);
- `
+ `,
),
],
});
diff --git a/tests/rules/no-topromise.test.ts b/tests/rules/no-topromise.test.ts
new file mode 100644
index 00000000..79e21249
--- /dev/null
+++ b/tests/rules/no-topromise.test.ts
@@ -0,0 +1,234 @@
+import { stripIndent } from 'common-tags';
+import { noTopromiseRule } from '../../src/rules/no-topromise';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('no-topromise', noTopromiseRule, {
+ valid: [
+ stripIndent`
+ // no toPromise
+ import { of, Subject } from "rxjs";
+ const a = of("a");
+ a.subscribe(value => console.log(value));
+ `,
+ stripIndent`
+ // non-observable toPromise
+ const a = {
+ toPromise() {
+ return Promise.resolve("a");
+ }
+ };
+ a.toPromise().then(value => console.log(value));
+ `,
+ stripIndent`
+ // no imports
+ class Observable {
+ toPromise() {
+ return Promise.resolve("a");
+ }
+ }
+ const a = new Observable();
+ a.toPromise().then(value => console.log(value));
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // observable toPromise
+ import { of } from "rxjs";
+ const a = of("a");
+ a.toPromise().then(value => console.log(value));
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // observable toPromise
+ import { of, lastValueFrom } from "rxjs";
+ const a = of("a");
+ lastValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // observable toPromise
+ import { of, firstValueFrom } from "rxjs";
+ const a = of("a");
+ firstValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // subject toPromise
+ import { Subject } from "rxjs";
+ const a = new Subject();
+ a.toPromise().then(value => console.log(value));
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // subject toPromise
+ import { Subject, lastValueFrom } from "rxjs";
+ const a = new Subject();
+ lastValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // subject toPromise
+ import { Subject, firstValueFrom } from "rxjs";
+ const a = new Subject();
+ firstValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // weird whitespace
+ import { of } from "rxjs";
+ const a = { foo$: of("a") };
+ a
+ .foo$
+ .toPromise().then(value => console.log(value))
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ .catch(error => console.error(error));
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // weird whitespace
+ import { of, lastValueFrom } from "rxjs";
+ const a = { foo$: of("a") };
+ lastValueFrom(a
+ .foo$).then(value => console.log(value))
+ .catch(error => console.error(error));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // weird whitespace
+ import { of, firstValueFrom } from "rxjs";
+ const a = { foo$: of("a") };
+ firstValueFrom(a
+ .foo$).then(value => console.log(value))
+ .catch(error => console.error(error));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // lastValueFrom already imported
+ import { lastValueFrom as lvf, of } from "rxjs";
+ const a = of("a");
+ a.toPromise().then(value => console.log(value));
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // lastValueFrom already imported
+ import { lastValueFrom as lvf, of } from "rxjs";
+ const a = of("a");
+ lvf(a).then(value => console.log(value));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // lastValueFrom already imported
+ import { lastValueFrom as lvf, of, firstValueFrom } from "rxjs";
+ const a = of("a");
+ firstValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // rxjs not already imported
+ import { fromFetch } from "rxjs/fetch";
+
+ const a = fromFetch("https://api.some.com");
+ a.toPromise().then(value => console.log(value));
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // rxjs not already imported
+ import { fromFetch } from "rxjs/fetch";
+ import { lastValueFrom } from "rxjs";
+
+ const a = fromFetch("https://api.some.com");
+ lastValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // rxjs not already imported
+ import { fromFetch } from "rxjs/fetch";
+ import { firstValueFrom } from "rxjs";
+
+ const a = fromFetch("https://api.some.com");
+ firstValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+ const a = Rx.of("a");
+ a.toPromise().then(value => console.log(value));
+ ~~~~~~~~~ [forbidden suggest 0 1]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggestLastValueFrom',
+ output: stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+ const a = Rx.of("a");
+ Rx.lastValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ {
+ messageId: 'suggestFirstValueFrom',
+ output: stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+ const a = Rx.of("a");
+ Rx.firstValueFrom(a).then(value => console.log(value));
+ `,
+ },
+ ],
+ },
+ ),
+ ],
+});
diff --git a/tests/rules/no-topromise.ts b/tests/rules/no-topromise.ts
deleted file mode 100644
index 395e208b..00000000
--- a/tests/rules/no-topromise.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-topromise");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-topromise", rule, {
- valid: [
- stripIndent`
- // no toPromise
- import { of, Subject } from "rxjs";
- const a = of("a");
- a.subscribe(value => console.log(value));
- `,
- stripIndent`
- // non-observable toPromise
- const a = {
- toPromise() {
- return Promise.resolve("a");
- }
- };
- a.toPromise().then(value => console.log(value));
- `,
- ],
- invalid: [
- fromFixture(
- stripIndent`
- // observable toPromise
- import { of } from "rxjs";
- const a = of("a");
- a.toPromise().then(value => console.log(value));
- ~~~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // subject toPromise
- import { Subject } from "rxjs";
- const a = new Subject();
- a.toPromise().then(value => console.log(value));
- ~~~~~~~~~ [forbidden]
- `
- ),
- ],
-});
diff --git a/tests/rules/no-unbound-methods.ts b/tests/rules/no-unbound-methods.test.ts
similarity index 92%
rename from tests/rules/no-unbound-methods.ts
rename to tests/rules/no-unbound-methods.test.ts
index 652c99e2..3bc85e3b 100644
--- a/tests/rules/no-unbound-methods.ts
+++ b/tests/rules/no-unbound-methods.test.ts
@@ -1,17 +1,12 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { TSESLint as eslint } from "@typescript-eslint/experimental-utils";
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unbound-methods");
-import { ruleTester } from "../utils";
+import { InvalidTestCase, ValidTestCase } from '@typescript-eslint/rule-tester';
+import { stripIndent } from 'common-tags';
+import { noUnboundMethodsRule } from '../../src/rules/no-unbound-methods';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
interface Tests {
- valid: (string | eslint.ValidTestCase)[];
- invalid: eslint.InvalidTestCase[];
+ valid: (string | ValidTestCase)[];
+ invalid: InvalidTestCase[];
}
const arrowTests: Tests = {
@@ -127,7 +122,7 @@ const deepTests: Tests = {
);
}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -146,7 +141,7 @@ const deepTests: Tests = {
~~~~~~~~~~~~~~~~~~ [forbidden]
}
}
- `
+ `,
),
],
};
@@ -228,7 +223,7 @@ const unboundTests: Tests = {
map(t: T): T { return t; }
catchError(error: any): Observable { return throwError(error); }
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -250,7 +245,7 @@ const unboundTests: Tests = {
error(error: any): void {}
complete(): void {}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -266,12 +261,12 @@ const unboundTests: Tests = {
}
tearDown(): void {}
}
- `
+ `,
),
],
};
-ruleTester({ types: true }).run("no-unbound-methods", rule, {
+ruleTester({ types: true }).run('no-unbound-methods', noUnboundMethodsRule, {
valid: [
...arrowTests.valid,
...boundTests.valid,
diff --git a/tests/rules/no-unsafe-catch.ts b/tests/rules/no-unsafe-catch.test.ts
similarity index 89%
rename from tests/rules/no-unsafe-catch.ts
rename to tests/rules/no-unsafe-catch.test.ts
index d78534b9..34bfc280 100644
--- a/tests/rules/no-unsafe-catch.ts
+++ b/tests/rules/no-unsafe-catch.test.ts
@@ -1,12 +1,7 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unsafe-catch");
-import { ruleTester } from "../utils";
+import { stripIndent } from 'common-tags';
+import { noUnsafeCatchRule } from '../../src/rules/no-unsafe-catch';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
const setup = stripIndent`
import { EMPTY, Observable, of } from "rxjs";
@@ -19,9 +14,9 @@ const setup = stripIndent`
type Actions = Observable;
const actions = of({});
const that = { actions };
-`.replace(/\n/g, "");
+`.replace(/\n/g, '');
-ruleTester({ types: true }).run("no-unsafe-catch", rule, {
+ruleTester({ types: true }).run('no-unsafe-catch', noUnsafeCatchRule, {
valid: [
{
code: stripIndent`
@@ -102,7 +97,7 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
catchError(() => EMPTY)
);
`,
- options: [{ observable: "foo" }],
+ options: [{ observable: 'foo' }],
},
],
invalid: [
@@ -117,7 +112,7 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
catchError(() => EMPTY)
~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -130,7 +125,7 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
catchError(() => EMPTY)
~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -143,7 +138,7 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
catchError(() => EMPTY)
~~~~~~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -160,10 +155,10 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
{
options: [
{
- observable: "foo",
+ observable: 'foo',
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -188,7 +183,7 @@ ruleTester({ types: true }).run("no-unsafe-catch", rule, {
~~~~~~~~~~ [forbidden]
);
}
- `
+ `,
),
],
});
diff --git a/tests/rules/no-unsafe-first.ts b/tests/rules/no-unsafe-first.test.ts
similarity index 90%
rename from tests/rules/no-unsafe-first.ts
rename to tests/rules/no-unsafe-first.test.ts
index d91a9332..a2d99e15 100644
--- a/tests/rules/no-unsafe-first.ts
+++ b/tests/rules/no-unsafe-first.test.ts
@@ -1,12 +1,7 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unsafe-first");
-import { ruleTester } from "../utils";
+import { stripIndent } from 'common-tags';
+import { noUnsafeFirstRule } from '../../src/rules/no-unsafe-first';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
const setup = stripIndent`
import { EMPTY, Observable, of } from "rxjs";
@@ -20,9 +15,9 @@ const setup = stripIndent`
const actions = of({});
const actions$ = of({});
const that = { actions };
-`.replace(/\n/g, "");
+`.replace(/\n/g, '');
-ruleTester({ types: true }).run("no-unsafe-first", rule, {
+ruleTester({ types: true }).run('no-unsafe-first', noUnsafeFirstRule, {
valid: [
{
code: stripIndent`
@@ -100,7 +95,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
first()
);
`,
- options: [{ observable: "foo" }],
+ options: [{ observable: 'foo' }],
},
{
code: stripIndent`
@@ -112,7 +107,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
first()
);
`,
- options: [{ observable: "foo" }],
+ options: [{ observable: 'foo' }],
},
{
code: stripIndent`
@@ -156,7 +151,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
first()
~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -169,7 +164,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
take(1)
~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -182,7 +177,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
first()
~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -195,7 +190,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
take(1)
~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -208,7 +203,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
first()
~~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -221,7 +216,7 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
take(1)
~~~~ [forbidden]
);
- `
+ `,
),
fromFixture(
stripIndent`
@@ -238,10 +233,10 @@ ruleTester({ types: true }).run("no-unsafe-first", rule, {
{
options: [
{
- observable: "foo",
+ observable: 'foo',
},
],
- }
+ },
),
],
});
diff --git a/tests/rules/no-unsafe-subject-next.ts b/tests/rules/no-unsafe-subject-next.test.ts
similarity index 79%
rename from tests/rules/no-unsafe-subject-next.ts
rename to tests/rules/no-unsafe-subject-next.test.ts
index e0586c72..f9d9dd76 100644
--- a/tests/rules/no-unsafe-subject-next.ts
+++ b/tests/rules/no-unsafe-subject-next.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noUnsafeSubjectNext } from '../../src/rules/no-unsafe-subject-next';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unsafe-subject-next");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-unsafe-subject-next", rule, {
+ruleTester({ types: true }).run('no-unsafe-subject-next', noUnsafeSubjectNext, {
valid: [
{
code: stripIndent`
@@ -78,7 +73,7 @@ ruleTester({ types: true }).run("no-unsafe-subject-next", rule, {
const s = new Subject();
s.next();
~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -87,7 +82,7 @@ ruleTester({ types: true }).run("no-unsafe-subject-next", rule, {
const s = new ReplaySubject();
s.next();
~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-unsafe-switchmap.ts b/tests/rules/no-unsafe-switchmap.test.ts
similarity index 92%
rename from tests/rules/no-unsafe-switchmap.ts
rename to tests/rules/no-unsafe-switchmap.test.ts
index f77944dc..503e5c2c 100644
--- a/tests/rules/no-unsafe-switchmap.ts
+++ b/tests/rules/no-unsafe-switchmap.test.ts
@@ -1,12 +1,7 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unsafe-switchmap");
-import { ruleTester } from "../utils";
+import { stripIndent } from 'common-tags';
+import { noUnsafeSwitchmapRule } from '../../src/rules/no-unsafe-switchmap';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
const setup = stripIndent`
import { EMPTY, Observable, of } from "rxjs";
@@ -23,9 +18,9 @@ const setup = stripIndent`
const PUT_SOMETHING = "PUT_SOMETHING";
const GetSomething = GET_SOMETHING;
const PutSomething = PUT_SOMETHING;
-`.replace(/\n/g, "");
+`.replace(/\n/g, '');
-ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
+ruleTester({ types: true }).run('no-unsafe-switchmap', noUnsafeSwitchmapRule, {
valid: [
{
code: stripIndent`
@@ -59,7 +54,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
`,
options: [
{
- allow: ["FOO"],
+ allow: ['FOO'],
},
],
},
@@ -72,7 +67,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
`,
options: [
{
- disallow: ["FOO"],
+ disallow: ['FOO'],
},
],
},
@@ -86,7 +81,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
~~~~~~~~~ [forbidden]
const pipedMorePutEffect = actions.pipe(ofType("DO_SOMETHING", "PUT_SOMETHING"), tap(() => {}), switchMap(() => EMPTY));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -96,7 +91,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
~~~~~~~~~ [forbidden]
const pipedMorePutEpic = (action$: Actions) => action$.pipe(ofType("DO_SOMETHING", "PUT_SOMETHING"), tap(() => {}), switchMap(() => EMPTY));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -106,7 +101,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
~~~~~~~~~ [forbidden]
const pipedOfTypeCamelCasePutEffect = actions.pipe(ofType(PutSomething), tap(() => {}), switchMap(() => EMPTY));
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -120,10 +115,10 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
{
options: [
{
- allow: ["FOO"],
+ allow: ['FOO'],
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -135,10 +130,10 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
{
options: [
{
- disallow: ["FOO"],
+ disallow: ['FOO'],
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -178,7 +173,7 @@ ruleTester({ types: true }).run("no-unsafe-switchmap", rule, {
const pipedOfTypeCamelCaseGetEffect = that.actions.pipe(ofType(Actions.types.GetSomething), tap(() => {}), switchMap(() => EMPTY));
const pipedOfTypeCamelCasePutEffect = that.actions.pipe(ofType(Actions.types.PutSomething), tap(() => {}), switchMap(() => EMPTY));
~~~~~~~~~ [forbidden]
- `
+ `,
),
],
});
diff --git a/tests/rules/no-unsafe-takeuntil.ts b/tests/rules/no-unsafe-takeuntil.test.ts
similarity index 92%
rename from tests/rules/no-unsafe-takeuntil.ts
rename to tests/rules/no-unsafe-takeuntil.test.ts
index 2539fc77..2b5475d1 100644
--- a/tests/rules/no-unsafe-takeuntil.ts
+++ b/tests/rules/no-unsafe-takeuntil.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { noUnsafeTakeuntilRule } from '../../src/rules/no-unsafe-takeuntil';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/no-unsafe-takeuntil");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
+ruleTester({ types: true }).run('no-unsafe-takeuntil', noUnsafeTakeuntilRule, {
valid: [
{
code: stripIndent`
@@ -120,7 +115,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
`,
options: [
{
- allow: ["tap"],
+ allow: ['tap'],
},
],
},
@@ -140,7 +135,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
`,
options: [
{
- alias: ["untilDestroyed"],
+ alias: ['untilDestroyed'],
},
],
},
@@ -164,7 +159,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
`,
options: [
{
- alias: ["untilDestroyed"],
+ alias: ['untilDestroyed'],
},
],
},
@@ -199,7 +194,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
const d = a.pipe(takeUntil(c), switchMap(_ => b)).subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -214,7 +209,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
const e = a.pipe(takeUntil(d), s => combineLatest(s, b, c)).subscribe();
~~~~~~~~~ [forbidden]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -232,10 +227,10 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
{
options: [
{
- allow: ["tap"],
+ allow: ['tap'],
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -263,7 +258,7 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
return output;
}
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -283,10 +278,10 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
{
options: [
{
- alias: ["untilDestroyed"],
+ alias: ['untilDestroyed'],
},
],
- }
+ },
),
fromFixture(
stripIndent`
@@ -306,10 +301,10 @@ ruleTester({ types: true }).run("no-unsafe-takeuntil", rule, {
{
options: [
{
- alias: ["untilDestroyed"],
+ alias: ['untilDestroyed'],
},
],
- }
+ },
),
],
});
diff --git a/tests/rules/prefer-observer.test.ts b/tests/rules/prefer-observer.test.ts
new file mode 100644
index 00000000..c6295ca6
--- /dev/null
+++ b/tests/rules/prefer-observer.test.ts
@@ -0,0 +1,1890 @@
+import { stripIndent } from 'common-tags';
+import { preferObserverRule } from '../../src/rules/prefer-observer';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('prefer-observer', preferObserverRule, {
+ valid: [
+ {
+ code: stripIndent`
+ // allow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe(
+ value => console.log(value)
+ );
+
+ source.subscribe({
+ next(value) { console.log(value); }
+ });
+ source.subscribe({
+ next: value => console.log(value)
+ });
+
+ source.pipe(tap(
+ value => console.log(value)
+ )).subscribe();
+
+ source.pipe(tap({
+ next(value) { console.log(value); }
+ })).subscribe();
+ source.pipe(tap({
+ next: value => console.log(value)
+ })).subscribe();
+ `,
+ options: [{ allowNext: true }],
+ },
+ {
+ code: stripIndent`
+ // default
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe();
+ source.subscribe(
+ value => console.log(value)
+ );
+
+ source.subscribe({
+ next(value) { console.log(value); }
+ });
+ source.subscribe({
+ error(error) { console.log(error); }
+ });
+ source.subscribe({
+ complete() { console.log("complete"); }
+ });
+ source.subscribe({
+ next(value) { console.log(value); },
+ error(error) { console.log(error); },
+ complete() { console.log("complete"); }
+ });
+
+ source.subscribe({
+ next: value => console.log(value)
+ });
+ source.subscribe({
+ error: error => console.log(error)
+ });
+ source.subscribe({
+ complete: () => console.log("complete")
+ });
+ source.subscribe({
+ next: value => console.log(value),
+ error: error => console.log(error),
+ complete: () => console.log("complete")
+ });
+
+ source.pipe(tap(
+ value => console.log(value)
+ )).subscribe();
+
+ source.pipe(tap({
+ next(value) { console.log(value); }
+ })).subscribe();
+ source.pipe(tap({
+ error(error) { console.log(error); }
+ })).subscribe();
+ source.pipe(tap({
+ complete() { console.log("complete"); }
+ })).subscribe();
+ source.pipe(tap({
+ next(value) { console.log(value); },
+ error(error) { console.log(error); },
+ complete() { console.log("complete"); }
+ })).subscribe();
+
+ source.pipe(tap({
+ next: value => console.log(value)
+ })).subscribe();
+ source.pipe(tap({
+ error: error => console.log(error)
+ })).subscribe();
+ source.pipe(tap({
+ complete: () => console.log("complete")
+ })).subscribe();
+ source.pipe(tap({
+ next: value => console.log(value),
+ error: error => console.log(error),
+ complete: () => console.log("complete")
+ })).subscribe();
+ `,
+ options: [{}],
+ },
+ {
+ code: stripIndent`
+ // disallow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe({
+ next(value) { console.log(value); }
+ });
+ source.subscribe({
+ next: value => console.log(value)
+ });
+
+ source.pipe(tap({
+ next(value) { console.log(value); }
+ })).subscribe();
+ source.pipe(tap({
+ next: value => console.log(value)
+ })).subscribe();
+ `,
+ options: [{ allowNext: false }],
+ },
+ {
+ code: stripIndent`
+ // named
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const nextObserver = {
+ next: (value: number) => { console.log(value); }
+ };
+ const source = of(42);
+
+ source.subscribe(nextObserver);
+ source.pipe(tap(nextObserver));
+ `,
+ options: [{}],
+ },
+ {
+ code: stripIndent`
+ // non-arrow functions
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe();
+ source.subscribe(
+ function (value) { console.log(value); }
+ );
+ source.pipe(tap(
+ function (value) { console.log(value); }
+ )).subscribe();
+ `,
+ options: [{}],
+ },
+ {
+ code: stripIndent`
+ // https://github.com/cartant/eslint-plugin-rxjs/issues/61
+ const whatever = {
+ pipe(...value: unknown[]) {},
+ subscribe(callback?: (value: unknown) => void) {}
+ };
+ whatever.pipe(() => {});
+ whatever.subscribe(() => {});
+ `,
+ options: [{ allowNext: false }],
+ },
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // default; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ value => console.log(value),
+ error => console.log(error)
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), error: error => console.log(error) }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), error: error => console.log(error) }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // default; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ value => console.log(value),
+ error => console.log(error),
+ () => console.log("complete")
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // default; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ value => console.log(value),
+ undefined,
+ () => console.log("complete")
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), complete: () => console.log("complete") }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value), complete: () => console.log("complete") }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // default; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ error => console.log(error)
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: error => console.log(error) }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: error => console.log(error) }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // default; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ error => console.log(error),
+ () => console.log("complete")
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: error => console.log(error), complete: () => console.log("complete") }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: error => console.log(error), complete: () => console.log("complete") }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // default; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ undefined,
+ () => console.log("complete")
+ );
+ `,
+ {
+ output: stripIndent`
+ // default; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { complete: () => console.log("complete") }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // default; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { complete: () => console.log("complete") }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ value => console.log(value),
+ error => console.log(error)
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), error: error => console.log(error) }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), error: error => console.log(error) }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ value => console.log(value),
+ error => console.log(error),
+ () => console.log("complete")
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ value => console.log(value),
+ undefined,
+ () => console.log("complete")
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: value => console.log(value), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ error => console.log(error)
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: error => console.log(error) }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: error => console.log(error) }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ error => console.log(error),
+ () => console.log("complete")
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: error => console.log(error), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: error => console.log(error), complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ undefined,
+ () => console.log("complete")
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { complete: () => console.log("complete") }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest 0]
+ value => console.log(value)
+ );
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest 1]
+ value => console.log(value)
+ )).subscribe();
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value) }
+ );
+
+ source.pipe(tap(
+ { next: value => console.log(value) }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: value => console.log(value) }
+ );
+
+ source.pipe(tap(
+ value => console.log(value)
+ )).subscribe();
+ `,
+ },
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.subscribe(
+ value => console.log(value)
+ );
+
+ source.pipe(tap(
+ { next: value => console.log(value) }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; named; next arrow
+ import { of } from "rxjs";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.subscribe(nextArrow);
+ ~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; named; next arrow
+ import { of } from "rxjs";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.subscribe({ next: nextArrow });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; named; next arrow
+ import { of } from "rxjs";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.subscribe({ next: nextArrow });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; named; next named
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.subscribe(nextNamed);
+ ~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; named; next named
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.subscribe({ next: nextNamed });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; named; next named
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.subscribe({ next: nextNamed });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; named; next non-arrow
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.subscribe(nextNonArrow);
+ ~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; named; next non-arrow
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.subscribe({ next: nextNonArrow });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; named; next non-arrow
+ import { of } from "rxjs";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.subscribe({ next: nextNonArrow });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; tap; named; next arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.pipe(tap(nextArrow));
+ ~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; tap; named; next arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.pipe(tap({ next: nextArrow }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; tap; named; next arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const nextArrow = (value: number) => { console.log(value); };
+ const source = of(42);
+
+ source.pipe(tap({ next: nextArrow }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; tap; named; next named
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.pipe(tap(nextNamed));
+ ~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; tap; named; next named
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.pipe(tap({ next: nextNamed }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; tap; named; next named
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const source = of(42);
+
+ source.pipe(tap({ next: nextNamed }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // disallow-next; tap; named; next non-arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.pipe(tap(nextNonArrow));
+ ~~~ [forbidden suggest]
+ `,
+ {
+ options: [{ allowNext: false }],
+ output: stripIndent`
+ // disallow-next; tap; named; next non-arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.pipe(tap({ next: nextNonArrow }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // disallow-next; tap; named; next non-arrow
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ function nextNamed(value: number): void { console.log(value); }
+ const nextNonArrow = nextNamed;
+ const source = of(42);
+
+ source.pipe(tap({ next: nextNonArrow }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ function (error) { console.log(error); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; next, error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ function (error) { console.log(error); },
+ function () { console.log("complete"); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; next, error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ undefined,
+ function () { console.log("complete"); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; next, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ function (error) { console.log(error); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: function (error) { console.log(error); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; error
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: function (error) { console.log(error); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ function (error) { console.log(error); },
+ function () { console.log("complete"); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; error, complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ ~~~~~~~~~ [forbidden suggest]
+ undefined,
+ undefined,
+ function () { console.log("complete"); }
+ );
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { complete: function () { console.log("complete"); } }
+ );
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; complete
+ import { of } from "rxjs";
+
+ const source = of(42);
+
+ source.subscribe(
+ { complete: function () { console.log("complete"); } }
+ );
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ function (error) { console.log(error); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; next, error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ function (error) { console.log(error); },
+ function () { console.log("complete"); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; next, error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ function (value) { console.log(value); },
+ undefined,
+ function () { console.log("complete"); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; next, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ function (error) { console.log(error); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: function (error) { console.log(error); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; error
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: function (error) { console.log(error); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ function (error) { console.log(error); },
+ function () { console.log("complete"); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; error, complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // non-arrow functions; tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ ~~~ [forbidden suggest]
+ undefined,
+ undefined,
+ function () { console.log("complete"); }
+ )).subscribe();
+ `,
+ {
+ output: stripIndent`
+ // non-arrow functions; tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ // non-arrow functions; tap; complete
+ import { of } from "rxjs";
+ import { tap } from "rxjs/operators";
+
+ const source = of(42);
+
+ source.pipe(tap(
+ { complete: function () { console.log("complete"); } }
+ )).subscribe();
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe(fn, fn, fn);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ next: fn, error: fn, complete: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ next: fn, error: fn, complete: fn });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe(fn, null, fn);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ next: fn, complete: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ next: fn, complete: fn });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe(null, undefined, fn);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ complete: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ complete: fn });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe(undefined, fn);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ error: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ error: fn });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe(undefined, fn, null);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ error: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ of(42).subscribe({ error: fn });
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).subscribe(undefined, fn, fn, fn, fn, fn, fn);
+ ~~~~~~~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).subscribe({ error: fn, complete: fn });
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).subscribe({ error: fn, complete: fn });
+ `,
+ },
+ ],
+ },
+ ),
+
+ // tap
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap(fn, fn, fn));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ next: fn, error: fn, complete: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ next: fn, error: fn, complete: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap(fn, null, fn));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ next: fn, complete: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ next: fn, complete: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap(null, undefined, fn));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ complete: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ complete: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap(undefined, fn));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ error: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ error: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap(undefined, fn, null));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ error: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ of(42).pipe(tap({ error: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).pipe(tap(undefined, fn, fn, fn, fn, fn, fn));
+ ~~~ [forbidden suggest 0]
+ `,
+ {
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).pipe(tap({ error: fn, complete: fn }));
+ `,
+ suggestions: [
+ {
+ messageId: 'forbidden',
+ output: stripIndent`
+ import { of, tap } from "rxjs";
+ const fn = () => {};
+
+ // super wrong
+ of(42).pipe(tap({ error: fn, complete: fn }));
+ `,
+ },
+ ],
+ },
+ ),
+ ],
+});
diff --git a/tests/rules/prefer-observer.ts b/tests/rules/prefer-observer.ts
deleted file mode 100644
index 7bf981b5..00000000
--- a/tests/rules/prefer-observer.ts
+++ /dev/null
@@ -1,879 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/prefer-observer");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("prefer-observer", rule, {
- valid: [
- {
- code: stripIndent`
- // allow-next
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- value => console.log(value)
- );
-
- source.subscribe({
- next(value) { console.log(value); }
- });
- source.subscribe({
- next: value => console.log(value)
- });
-
- source.pipe(tap(
- value => console.log(value)
- )).subscribe();
-
- source.pipe(tap({
- next(value) { console.log(value); }
- })).subscribe();
- source.pipe(tap({
- next: value => console.log(value)
- })).subscribe();
- `,
- options: [{ allowNext: true }],
- },
- {
- code: stripIndent`
- // default
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe();
- source.subscribe(
- value => console.log(value)
- );
-
- source.subscribe({
- next(value) { console.log(value); }
- });
- source.subscribe({
- error(error) { console.log(error); }
- });
- source.subscribe({
- complete() { console.log("complete"); }
- });
- source.subscribe({
- next(value) { console.log(value); },
- error(error) { console.log(error); },
- complete() { console.log("complete"); }
- });
-
- source.subscribe({
- next: value => console.log(value)
- });
- source.subscribe({
- error: error => console.log(error)
- });
- source.subscribe({
- complete: () => console.log("complete")
- });
- source.subscribe({
- next: value => console.log(value),
- error: error => console.log(error),
- complete: () => console.log("complete")
- });
-
- source.pipe(tap(
- value => console.log(value)
- )).subscribe();
-
- source.pipe(tap({
- next(value) { console.log(value); }
- })).subscribe();
- source.pipe(tap({
- error(error) { console.log(error); }
- })).subscribe();
- source.pipe(tap({
- complete() { console.log("complete"); }
- })).subscribe();
- source.pipe(tap({
- next(value) { console.log(value); },
- error(error) { console.log(error); },
- complete() { console.log("complete"); }
- })).subscribe();
-
- source.pipe(tap({
- next: value => console.log(value)
- })).subscribe();
- source.pipe(tap({
- error: error => console.log(error)
- })).subscribe();
- source.pipe(tap({
- complete: () => console.log("complete")
- })).subscribe();
- source.pipe(tap({
- next: value => console.log(value),
- error: error => console.log(error),
- complete: () => console.log("complete")
- })).subscribe();
- `,
- options: [{}],
- },
- {
- code: stripIndent`
- // disallow-next
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe({
- next(value) { console.log(value); }
- });
- source.subscribe({
- next: value => console.log(value)
- });
-
- source.pipe(tap({
- next(value) { console.log(value); }
- })).subscribe();
- source.pipe(tap({
- next: value => console.log(value)
- })).subscribe();
- `,
- options: [{ allowNext: false }],
- },
- {
- code: stripIndent`
- // named
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const nextObserver = {
- next: (value: number) => { console.log(value); }
- };
- const source = of(42);
-
- source.subscribe(nextObserver);
- source.pipe(tap(nextObserver));
- `,
- options: [{}],
- },
- {
- code: stripIndent`
- // non-arrow functions
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe();
- source.subscribe(
- function (value) { console.log(value); }
- );
- source.pipe(tap(
- function (value) { console.log(value); }
- )).subscribe();
- `,
- options: [{}],
- },
- {
- code: stripIndent`
- // https://github.com/cartant/eslint-plugin-rxjs/issues/61
- const whatever = {
- pipe(...value: unknown[]) {},
- subscribe(callback?: (value: unknown) => void) {}
- };
- whatever.pipe(() => {});
- whatever.subscribe(() => {});
- `,
- options: [{ allowNext: false }],
- },
- ],
- invalid: [
- fromFixture(
- stripIndent`
- // default
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- value => console.log(value),
- error => console.log(error)
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- value => console.log(value),
- error => console.log(error),
- () => console.log("complete")
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- value => console.log(value),
- undefined,
- () => console.log("complete")
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- error => console.log(error)
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- error => console.log(error),
- () => console.log("complete")
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- undefined,
- () => console.log("complete")
- );
-
- source.pipe(tap(
- ~~~ [forbidden]
- value => console.log(value),
- error => console.log(error)
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- value => console.log(value),
- error => console.log(error),
- () => console.log("complete")
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- value => console.log(value),
- undefined,
- () => console.log("complete")
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- error => console.log(error)
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- error => console.log(error),
- () => console.log("complete")
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- undefined,
- () => console.log("complete")
- )).subscribe();
- `,
- {
- output: stripIndent`
- // default
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- { next: value => console.log(value), error: error => console.log(error) }
- );
- source.subscribe(
- { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
- );
- source.subscribe(
- { next: value => console.log(value), complete: () => console.log("complete") }
- );
- source.subscribe(
- { error: error => console.log(error) }
- );
- source.subscribe(
- { error: error => console.log(error), complete: () => console.log("complete") }
- );
- source.subscribe(
- { complete: () => console.log("complete") }
- );
-
- source.pipe(tap(
- { next: value => console.log(value), error: error => console.log(error) }
- )).subscribe();
- source.pipe(tap(
- { next: value => console.log(value), error: error => console.log(error), complete: () => console.log("complete") }
- )).subscribe();
- source.pipe(tap(
- { next: value => console.log(value), complete: () => console.log("complete") }
- )).subscribe();
- source.pipe(tap(
- { error: error => console.log(error) }
- )).subscribe();
- source.pipe(tap(
- { error: error => console.log(error), complete: () => console.log("complete") }
- )).subscribe();
- source.pipe(tap(
- { complete: () => console.log("complete") }
- )).subscribe();
- `,
- }
- ),
- fromFixture(
- stripIndent`
- // disallow-next
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- value => console.log(value)
- );
-
- source.pipe(tap(
- ~~~ [forbidden]
- value => console.log(value)
- )).subscribe();
- `,
- {
- options: [{ allowNext: false }],
- output: stripIndent`
- // disallow-next
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- { next: value => console.log(value) }
- );
-
- source.pipe(tap(
- { next: value => console.log(value) }
- )).subscribe();
- `,
- }
- ),
- fromFixture(
- stripIndent`
- // named
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const nextArrow = (value: number) => { console.log(value); };
- function nextNamed(value: number): void { console.log(value); }
- const nextNonArrow = nextNamed;
-
- const source = of(42);
-
- source.subscribe(nextArrow);
- ~~~~~~~~~ [forbidden]
- source.subscribe(nextNamed);
- ~~~~~~~~~ [forbidden]
- source.subscribe(nextNonArrow);
- ~~~~~~~~~ [forbidden]
-
- source.pipe(tap(nextArrow));
- ~~~ [forbidden]
- source.pipe(tap(nextNamed));
- ~~~ [forbidden]
- source.pipe(tap(nextNonArrow));
- ~~~ [forbidden]
- `,
- {
- options: [{ allowNext: false }],
- output: stripIndent`
- // named
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const nextArrow = (value: number) => { console.log(value); };
- function nextNamed(value: number): void { console.log(value); }
- const nextNonArrow = nextNamed;
-
- const source = of(42);
-
- source.subscribe({ next: nextArrow });
- source.subscribe({ next: nextNamed });
- source.subscribe({ next: nextNonArrow });
-
- source.pipe(tap({ next: nextArrow }));
- source.pipe(tap({ next: nextNamed }));
- source.pipe(tap({ next: nextNonArrow }));
- `,
- }
- ),
- fromFixture(
- stripIndent`
- // non-arrow functions
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- function (value) { console.log(value); },
- function (error) { console.log(error); }
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- function (value) { console.log(value); },
- function (error) { console.log(error); },
- function () { console.log("complete"); }
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- function (value) { console.log(value); },
- undefined,
- function () { console.log("complete"); }
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- function (error) { console.log(error); }
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- function (error) { console.log(error); },
- function () { console.log("complete"); }
- );
- source.subscribe(
- ~~~~~~~~~ [forbidden]
- undefined,
- undefined,
- function () { console.log("complete"); }
- );
-
- source.pipe(tap(
- ~~~ [forbidden]
- function (value) { console.log(value); },
- function (error) { console.log(error); }
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- function (value) { console.log(value); },
- function (error) { console.log(error); },
- function () { console.log("complete"); }
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- function (value) { console.log(value); },
- undefined,
- function () { console.log("complete"); }
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- function (error) { console.log(error); }
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- function (error) { console.log(error); },
- function () { console.log("complete"); }
- )).subscribe();
- source.pipe(tap(
- ~~~ [forbidden]
- undefined,
- undefined,
- function () { console.log("complete"); }
- )).subscribe();
- `,
- {
- output: stripIndent`
- // non-arrow functions
- import { of } from "rxjs";
- import { tap } from "rxjs/operators";
-
- const source = of(42);
-
- source.subscribe(
- { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
- );
- source.subscribe(
- { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
- );
- source.subscribe(
- { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
- );
- source.subscribe(
- { error: function (error) { console.log(error); } }
- );
- source.subscribe(
- { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
- );
- source.subscribe(
- { complete: function () { console.log("complete"); } }
- );
-
- source.pipe(tap(
- { next: function (value) { console.log(value); }, error: function (error) { console.log(error); } }
- )).subscribe();
- source.pipe(tap(
- { next: function (value) { console.log(value); }, error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
- )).subscribe();
- source.pipe(tap(
- { next: function (value) { console.log(value); }, complete: function () { console.log("complete"); } }
- )).subscribe();
- source.pipe(tap(
- { error: function (error) { console.log(error); } }
- )).subscribe();
- source.pipe(tap(
- { error: function (error) { console.log(error); }, complete: function () { console.log("complete"); } }
- )).subscribe();
- source.pipe(tap(
- { complete: function () { console.log("complete"); } }
- )).subscribe();
- `,
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe(fn, fn, fn);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ next: fn, error: fn, complete: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ next: fn, error: fn, complete: fn });
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe(fn, null, fn);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ next: fn, complete: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ next: fn, complete: fn });
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe(null, undefined, fn);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ complete: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ complete: fn });
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe(undefined, fn);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ error: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ error: fn });
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe(undefined, fn, null);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ error: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- of(42).subscribe({ error: fn });
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).subscribe(undefined, fn, fn, fn, fn, fn, fn);
- ~~~~~~~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).subscribe({ error: fn, complete: fn });
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).subscribe({ error: fn, complete: fn });
- `,
- },
- ],
- }
- ),
-
- // tap
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap(fn, fn, fn));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ next: fn, error: fn, complete: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ next: fn, error: fn, complete: fn }));
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap(fn, null, fn));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ next: fn, complete: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ next: fn, complete: fn }));
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap(null, undefined, fn));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ complete: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ complete: fn }));
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap(undefined, fn));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ error: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ error: fn }));
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap(undefined, fn, null));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ error: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- of(42).pipe(tap({ error: fn }));
- `,
- },
- ],
- }
- ),
- fromFixture(
- stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).pipe(tap(undefined, fn, fn, fn, fn, fn, fn));
- ~~~ [forbidden suggest 0]
- `,
- {
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).pipe(tap({ error: fn, complete: fn }));
- `,
- suggestions: [
- {
- messageId: "forbidden",
- output: stripIndent`
- import { of, tap } from "rxjs";
- const fn = () => {};
-
- // super wrong
- of(42).pipe(tap({ error: fn, complete: fn }));
- `,
- },
- ],
- }
- ),
- ],
-});
diff --git a/tests/rules/prefer-root-operators.test.ts b/tests/rules/prefer-root-operators.test.ts
new file mode 100644
index 00000000..4627b494
--- /dev/null
+++ b/tests/rules/prefer-root-operators.test.ts
@@ -0,0 +1,235 @@
+import { stripIndent } from 'common-tags';
+import { preferRootOperatorsRule } from '../../src/rules/prefer-root-operators';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: false }).run('prefer-root-operators', preferRootOperatorsRule, {
+ valid: [
+ stripIndent`
+ // import declaration named
+ import { concatWith } from "rxjs";
+ import { mergeWith } from 'rxjs';
+ `,
+ stripIndent`
+ // import declaration namespace
+ import * as Rx from "rxjs";
+ `,
+ stripIndent`
+ // import expression
+ const { concatWith } = await import("rxjs");
+ `,
+ stripIndent`
+ // import expression without a string literal is not supported
+ const path = "rxjs/operators";
+ const { concat } = await import(path);
+ `,
+ stripIndent`
+ // export named
+ export { concatWith, mergeWith as m } from "rxjs";
+ `,
+ stripIndent`
+ // export all
+ export * from "rxjs";
+ `,
+ stripIndent`
+ // unrelated import
+ import { ajax } from "rxjs/ajax";
+ import { fromFetch } from "rxjs/fetch";
+ import { TestScheduler } from "rxjs/testing";
+ import { webSocket } from "rxjs/webSocket";
+ import * as prefixedPackage from "rxjs-prefixed-package";
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // import declaration named
+ import { map as m, filter, 'tap' as tap } from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ output: stripIndent`
+ // import declaration named
+ import { map as m, filter, 'tap' as tap } from "rxjs";
+ `,
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import declaration named
+ import { map as m, filter, 'tap' as tap } from "rxjs";
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import declaration named, renamed operators
+ import { 'merge' as m, race as race } from 'rxjs/operators';
+ ~~~~~~~~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ output: stripIndent`
+ // import declaration named, renamed operators
+ import { 'mergeWith' as m, raceWith as race } from 'rxjs';
+ `,
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import declaration named, renamed operators
+ import { 'mergeWith' as m, raceWith as race } from 'rxjs';
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import declaration named, deprecated operator
+ import { partition } from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // import declaration namespace
+ import * as RxOperators from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import declaration namespace
+ import * as RxOperators from "rxjs";
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import declaration default
+ import RxOperators, { map } from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import declaration default
+ import RxOperators, { map } from "rxjs";
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import expression
+ const { concat, merge: m, map } = await import("rxjs/operators");
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import expression
+ const { concat, merge: m, map } = await import("rxjs");
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import expression, separated import
+ const opPromise = import("rxjs/operators");
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ const { concat } = await opPromise;
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import expression, separated import
+ const opPromise = import("rxjs");
+ const { concat } = await opPromise;
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // import expression, deprecated operator
+ const { concat, partition } = await import("rxjs/operators");
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // import expression, deprecated operator
+ const { concat, partition } = await import("rxjs");
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // export named
+ export { concat, merge as m, map, 'race' as "r" } from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbidden suggest]
+ `,
+ {
+ output: stripIndent`
+ // export named
+ export { concatWith as concat, mergeWith as m, map, 'raceWith' as "r" } from "rxjs";
+ `,
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // export named
+ export { concatWith as concat, mergeWith as m, map, 'raceWith' as "r" } from "rxjs";
+ `,
+ },
+ ],
+ },
+ ),
+ fromFixture(
+ stripIndent`
+ // export named, deprecated operator
+ export { concat, partition } from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // export all
+ export * from "rxjs/operators";
+ ~~~~~~~~~~~~~~~~ [forbiddenWithoutFix suggest]
+ `,
+ {
+ suggestions: [
+ {
+ messageId: 'suggest',
+ output: stripIndent`
+ // export all
+ export * from "rxjs";
+ `,
+ },
+ ],
+ },
+ ),
+ ],
+});
diff --git a/tests/rules/suffix-subjects.ts b/tests/rules/suffix-subjects.test.ts
similarity index 95%
rename from tests/rules/suffix-subjects.ts
rename to tests/rules/suffix-subjects.test.ts
index 57e49c6a..5365d6b5 100644
--- a/tests/rules/suffix-subjects.ts
+++ b/tests/rules/suffix-subjects.test.ts
@@ -1,14 +1,9 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
+import { stripIndent } from 'common-tags';
+import { suffixSubjectsRule } from '../../src/rules/suffix-subjects';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/suffix-subjects");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("suffix-subjects", rule, {
+ruleTester({ types: true }).run('suffix-subjects', suffixSubjectsRule, {
valid: [
{
code: stripIndent`
@@ -152,7 +147,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
(someSub: Subject): void;
}
`,
- options: [{ suffix: "Sub" }],
+ options: [{ suffix: 'Sub' }],
},
{
code: stripIndent`
@@ -201,7 +196,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
}
`,
- options: [{ suffix: "Sub" }],
+ options: [{ suffix: 'Sub' }],
},
{
code: stripIndent`
@@ -224,7 +219,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
options: [
{
types: {
- "^Thing$": false,
+ '^Thing$': false,
},
},
],
@@ -331,7 +326,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
(some: Subject): void;
~~~~ [forbidden { "suffix": "Subject" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -368,7 +363,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
(some: Subject): void;
}
`,
- { options: [{ parameters: false }] }
+ { options: [{ parameters: false }] },
),
fromFixture(
stripIndent`
@@ -413,7 +408,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
~~~~ [forbidden { "suffix": "Sub" }]
}
`,
- { options: [{ suffix: "Sub" }] }
+ { options: [{ suffix: 'Sub' }] },
),
fromFixture(
stripIndent`
@@ -450,7 +445,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
some: Subject;
~~~~ [forbidden { "suffix": "Subject" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -480,7 +475,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
some: Subject;
}
`,
- { options: [{ properties: false }] }
+ { options: [{ properties: false }] },
),
fromFixture(
stripIndent`
@@ -518,7 +513,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
~~~~ [forbidden { "suffix": "Sub" }]
}
`,
- { options: [{ suffix: "Sub" }] }
+ { options: [{ suffix: 'Sub' }] },
),
fromFixture(
stripIndent`
@@ -529,7 +524,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
~~~ [forbidden { "suffix": "Subject" }]
const some = new Subject();
~~~~ [forbidden { "suffix": "Subject" }]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -541,7 +536,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
const some = new Subject();
~~~~ [forbidden { "suffix": "Sub" }]
`,
- { options: [{ suffix: "Sub" }] }
+ { options: [{ suffix: 'Sub' }] },
),
fromFixture(
stripIndent`
@@ -555,7 +550,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
someMethod([someParam]: Subject[]): void {}
~~~~~~~~~ [forbidden { "suffix": "Subject" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -569,7 +564,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
someMethod({ source }: Record>): void {}
~~~~~~ [forbidden { "suffix": "Subject" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -580,7 +575,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
constructor(public some: Subject) {}
~~~~ [forbidden { "suffix": "Subject" }]
}
- `
+ `,
),
fromFixture(
stripIndent`
@@ -589,7 +584,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
const source = new BehaviorSubject(42);
~~~~~~ [forbidden { "suffix": "Subject" }]
- `
+ `,
),
fromFixture(
stripIndent`
@@ -602,7 +597,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
const someSubject$ = new BehaviorSubject(54);
~~~~~~~~~~~~ [forbidden { "suffix": "$$" }]
`,
- { options: [{ suffix: "$$" }] }
+ { options: [{ suffix: '$$' }] },
),
fromFixture(
stripIndent`
@@ -615,7 +610,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
~~~~~~~~~~~~~ [forbidden { "suffix": "$$" }]
}
`,
- { options: [{ suffix: "$$" }] }
+ { options: [{ suffix: '$$' }] },
),
fromFixture(
stripIndent`
@@ -625,7 +620,7 @@ ruleTester({ types: true }).run("suffix-subjects", rule, {
const source = new MySubject();
~~~~~~ [forbidden { "suffix": "Subject" }]
- `
+ `,
),
],
});
diff --git a/tests/rules/throw-error.test.ts b/tests/rules/throw-error.test.ts
new file mode 100644
index 00000000..6c51c954
--- /dev/null
+++ b/tests/rules/throw-error.test.ts
@@ -0,0 +1,268 @@
+import { stripIndent } from 'common-tags';
+import { throwErrorRule } from '../../src/rules/throw-error';
+import { fromFixture } from '../etc';
+import { ruleTester } from '../rule-tester';
+
+ruleTester({ types: true }).run('throw-error', throwErrorRule, {
+ valid: [
+ stripIndent`
+ // Error
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => new Error("Boom!"));
+ `,
+ stripIndent`
+ // RangeError
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => new RangeError("Boom!"));
+ `,
+ stripIndent`
+ // DOMException
+ ///
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => new DOMException("Boom!"));
+ `,
+ stripIndent`
+ // custom Error
+ import { throwError } from "rxjs";
+
+ class MyFailure extends Error {}
+
+ const ob1 = throwError(() => new MyFailure("Boom!"));
+ `,
+ stripIndent`
+ // arrow function return
+ import { throwError } from "rxjs";
+
+ throwError(() => {
+ return new Error("Boom!");
+ });
+ `,
+ stripIndent`
+ // function return
+ import { throwError } from "rxjs";
+
+ throwError(function () {
+ return new Error("Boom!");
+ });
+ `,
+ stripIndent`
+ // any
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => "Boom!" as any);
+ `,
+ stripIndent`
+ // returned any
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => errorMessage());
+
+ function errorMessage(): any {
+ return "error";
+ }
+ `,
+ stripIndent`
+ // unknown
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => "Boom!" as unknown);
+ `,
+ stripIndent`
+ // returned unknown
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => errorMessage());
+
+ function errorMessage(): unknown {
+ return "error";
+ }
+ `,
+ stripIndent`
+ // Error without factory (deprecated)
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(new Error("Boom!"));
+ `,
+ stripIndent`
+ // DOMException without factory (deprecated)
+ ///
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(new DOMException("Boom!"));
+ `,
+ stripIndent`
+ // any without factory (deprecated)
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError("Boom!" as any);
+ `,
+ stripIndent`
+ // returned any without factory (deprecated)
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(errorMessage());
+
+ function errorMessage(): any {
+ return "error";
+ }
+ `,
+ stripIndent`
+ // Object.assign
+ // https://github.com/cartant/rxjs-tslint-rules/issues/86
+ import { throwError } from "rxjs";
+
+ throwError(() => Object.assign(
+ new Error("Not Found"),
+ { code: "NOT_FOUND" }
+ ));
+ `,
+ stripIndent`
+ // Object.assign arrow function return
+ import { throwError } from "rxjs";
+
+ throwError(() => {
+ return Object.assign(
+ new Error("Not Found"),
+ { code: "NOT_FOUND" }
+ );
+ });
+ `,
+ stripIndent`
+ // no signature
+ // There will be no signature for callback and
+ // that should not effect an internal error.
+ declare const callback: Function;
+ callback();
+ `,
+ stripIndent`
+ // unrelated throw statements (use @typescript-eslint/only-throw-error instead).
+ const a = () => { throw "error"; };
+ const b = () => { throw new Error("error"); };
+
+ const errorMessage = "Boom!";
+ const c = () => { throw errorMessage; };
+
+ const d = () => { throw errorMessage(); };
+ function errorMessage() {
+ return "error";
+ }
+
+ const e = () => { throw new DOMException("error"); };
+ const f = () => { throw "error" as any };
+
+ const g = () => { throw errorMessageAny(); };
+ function errorMessageAny(): any {
+ return "error";
+ }
+
+ https://github.com/cartant/rxjs-tslint-rules/issues/85
+ try {
+ throw new Error("error");
+ } catch (error: any) {
+ throw error;
+ }
+ `,
+ ],
+ invalid: [
+ fromFixture(
+ stripIndent`
+ // string
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => "Boom!");
+ ~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // returned string
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => errorMessage());
+ ~~~~~~~~~~~~~~ [forbidden]
+
+ function errorMessage() {
+ return "Boom!";
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // string without factory (deprecated)
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError("Boom!");
+ ~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // returned string without factory (deprecated)
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(errorMessage());
+ ~~~~~~~~~~~~~~ [forbidden]
+
+ function errorMessage() {
+ return "Boom!";
+ }
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // any not allowed
+ import { throwError } from "rxjs";
+
+ throwError(() => "Boom!" as any);
+ ~~~~~~~~~~~~~~ [forbidden]
+ `,
+ { options: [{ allowThrowingAny: false }] },
+ ),
+ fromFixture(
+ stripIndent`
+ // unknown not allowed
+ import { throwError } from "rxjs";
+
+ throwError(() => "Boom!" as unknown);
+ ~~~~~~~~~~~~~~~~~~ [forbidden]
+ `,
+ { options: [{ allowThrowingUnknown: false }] },
+ ),
+ fromFixture(
+ stripIndent`
+ // falsy
+ import { throwError } from "rxjs";
+
+ const ob1 = throwError(() => 0);
+ ~ [forbidden]
+ const ob2 = throwError(() => false);
+ ~~~~~ [forbidden]
+ const ob3 = throwError(() => null);
+ ~~~~ [forbidden]
+ const ob4 = throwError(() => undefined);
+ ~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // Object.assign with non-Error
+ import { throwError } from "rxjs";
+
+ throwError(() => Object.assign({ message: "Not Found" }, { code: "NOT_FOUND" }));
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbidden]
+ `,
+ ),
+ fromFixture(
+ stripIndent`
+ // namespace import
+ import * as Rx from "rxjs";
+
+ Rx.throwError(() => "Boom!");
+ ~~~~~~~ [forbidden]
+ `,
+ ),
+ ],
+});
diff --git a/tests/rules/throw-error.ts b/tests/rules/throw-error.ts
deleted file mode 100644
index bdf07aaf..00000000
--- a/tests/rules/throw-error.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { stripIndent } from "common-tags";
-import { fromFixture } from "eslint-etc";
-import rule = require("../../source/rules/throw-error");
-import { ruleTester } from "../utils";
-
-ruleTester({ types: true }).run("throw-error", rule, {
- valid: [
- stripIndent`
- // throw Error
- const a = () => { throw new Error("error"); };
- `,
- stripIndent`
- // throw DOMException
- const a = () => { throw new DOMException("error"); };
- `,
- stripIndent`
- // throw any
- const a = () => { throw "error" as any };
- `,
- stripIndent`
- // throw returned any
- const a = () => { throw errorMessage(); };
-
- function errorMessage(): any {
- return "error";
- }
- `,
- stripIndent`
- // throwError Error
- import { throwError } from "rxjs";
-
- const ob1 = throwError(new Error("Boom!"));
- `,
- stripIndent`
- // throwError DOMException
- import { throwError } from "rxjs";
-
- const ob1 = throwError(new DOMException("Boom!"));
- `,
- stripIndent`
- // throwError any
- import { throwError } from "rxjs";
-
- const ob1 = throwError("Boom!" as any);
- `,
- stripIndent`
- // throwError returned any
- import { throwError } from "rxjs";
-
- const ob1 = throwError(errorMessage());
-
- function errorMessage(): any {
- return "error";
- }
- `,
- stripIndent`
- // throwError unknown
- import { throwError } from "rxjs";
-
- const ob1 = throwError("Boom!" as unknown);
- `,
- stripIndent`
- // throwError returned unknown
- import { throwError } from "rxjs";
-
- const ob1 = throwError(errorMessage());
-
- function errorMessage(): unknown {
- return "error";
- }
- `,
- stripIndent`
- // throwError Error with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => new Error("Boom!"));
- `,
- stripIndent`
- // throwError DOMException with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => new DOMException("Boom!"));
- `,
- stripIndent`
- // throwError any with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => "Boom!" as any);
- `,
- stripIndent`
- // throwError returned any with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => errorMessage());
-
- function errorMessage(): any {
- return "error";
- }
- `,
- stripIndent`
- // no signature
- // There will be no signature for callback and
- // that should not effect an internal error.
- declare const callback: Function;
- callback();
- `,
- stripIndent`
- https://github.com/cartant/rxjs-tslint-rules/issues/85
- try {
- throw new Error("error");
- } catch (error: any) {
- throw error;
- }
- `,
- ],
- invalid: [
- fromFixture(
- stripIndent`
- // throw string
- const a = () => { throw "error"; };
- ~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // throw returned string
- const a = () => { throw errorMessage(); };
- ~~~~~~~~~~~~~~ [forbidden]
-
- function errorMessage() {
- return "error";
- }
- `
- ),
- fromFixture(
- stripIndent`
- // throw string variable
- const errorMessage = "Boom!";
-
- const a = () => { throw errorMessage; };
- ~~~~~~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // throwError string
- import { throwError } from "rxjs";
-
- const ob1 = throwError("Boom!");
- ~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // throwError returned string
- import { throwError } from "rxjs";
-
- const ob1 = throwError(errorMessage());
- ~~~~~~~~~~~~~~ [forbidden]
-
- function errorMessage() {
- return "Boom!";
- }
- `
- ),
- fromFixture(
- stripIndent`
- https://github.com/cartant/rxjs-tslint-rules/issues/86
- const a = () => { throw "error"; };
- ~~~~~~~ [forbidden]
- const b = () => { throw new Error("error"); };
- const c = () => {
- throw Object.assign(
- new Error("Not Found"),
- { code: "NOT_FOUND" }
- );
- };
- `
- ),
- fromFixture(
- stripIndent`
- // throwError string with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => "Boom!");
- ~~~~~~~~~~~~~ [forbidden]
- `
- ),
- fromFixture(
- stripIndent`
- // throwError returned string with factory
- import { throwError } from "rxjs";
-
- const ob1 = throwError(() => errorMessage());
- ~~~~~~~~~~~~~~~~~~~~ [forbidden]
-
- function errorMessage() {
- return "Boom!";
- }
- `
- ),
- ],
-});
diff --git a/tests/tsconfig.json b/tests/tsconfig.json
deleted file mode 100644
index cdba13a1..00000000
--- a/tests/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "compilerOptions": {
- "lib": ["esnext"],
- "module": "commonjs",
- "moduleResolution": "node",
- "skipLibCheck": true,
- "target": "esnext"
- },
- "files": ["file.tsx"]
-}
diff --git a/tests/utils-spec.ts b/tests/utils-spec.ts
deleted file mode 100644
index f5b9fb3e..00000000
--- a/tests/utils-spec.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { expect } from "chai";
-import decamelize from "decamelize";
-import { createRegExpForWords } from "../source/utils";
-
-describe("utils", () => {
- describe("createRegExpForWords", () => {
- const regExp = createRegExpForWords(["add"]) as RegExp;
-
- it("should match action literals", () => {
- expect(`"ADD"`).to.match(regExp);
- expect(`"ADD_SOMETHING"`).to.match(regExp);
- expect(`"SOMETHING_ADD"`).to.match(regExp);
-
- expect(`'ADD'`).to.match(regExp);
- expect(`'ADD_SOMETHING'`).to.match(regExp);
- expect(`'SOMETHING_ADD'`).to.match(regExp);
-
- expect("`ADD`").to.match(regExp);
- expect("`ADD_SOMETHING`").to.match(regExp);
- expect("`SOMETHING_ADD`").to.match(regExp);
- });
-
- it("should match action symbols", () => {
- expect("ADD").to.match(regExp);
- expect("ADD_SOMETHING").to.match(regExp);
- expect("SOMETHING_ADD").to.match(regExp);
-
- expect(decamelize("Add")).to.match(regExp);
- expect(decamelize("AddSomething")).to.match(regExp);
- expect(decamelize("SomethingAdd")).to.match(regExp);
- });
-
- it("should not match words within larger words", () => {
- expect("READD").to.not.match(regExp);
- expect("Readd").to.not.match(regExp);
-
- expect("ADDER").to.not.match(regExp);
- expect("Adder").to.not.match(regExp);
-
- expect("LADDER").to.not.match(regExp);
- expect("Ladder").to.not.match(regExp);
- });
-
- it("should create a RegExp from a string", () => {
- expect((createRegExpForWords(".") as RegExp).toString()).to.equal("/./i");
- });
- });
-});
diff --git a/tests/utils.test.ts b/tests/utils.test.ts
new file mode 100644
index 00000000..b92dd048
--- /dev/null
+++ b/tests/utils.test.ts
@@ -0,0 +1,48 @@
+import decamelize from 'decamelize';
+import { createRegExpForWords } from '../src/utils';
+
+describe('utils', () => {
+ describe('createRegExpForWords', () => {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const regExp = createRegExpForWords(['add'])!;
+
+ it('should match action literals', () => {
+ expect(`"ADD"`).toMatch(regExp);
+ expect(`"ADD_SOMETHING"`).toMatch(regExp);
+ expect(`"SOMETHING_ADD"`).toMatch(regExp);
+
+ expect(`'ADD'`).toMatch(regExp);
+ expect(`'ADD_SOMETHING'`).toMatch(regExp);
+ expect(`'SOMETHING_ADD'`).toMatch(regExp);
+
+ expect('`ADD`').toMatch(regExp);
+ expect('`ADD_SOMETHING`').toMatch(regExp);
+ expect('`SOMETHING_ADD`').toMatch(regExp);
+ });
+
+ it('should match action symbols', () => {
+ expect('ADD').toMatch(regExp);
+ expect('ADD_SOMETHING').toMatch(regExp);
+ expect('SOMETHING_ADD').toMatch(regExp);
+
+ expect(decamelize('Add')).toMatch(regExp);
+ expect(decamelize('AddSomething')).toMatch(regExp);
+ expect(decamelize('SomethingAdd')).toMatch(regExp);
+ });
+
+ it('should not match words within larger words', () => {
+ expect('READD').not.toMatch(regExp);
+ expect('Readd').not.toMatch(regExp);
+
+ expect('ADDER').not.toMatch(regExp);
+ expect('Adder').not.toMatch(regExp);
+
+ expect('LADDER').not.toMatch(regExp);
+ expect('Ladder').not.toMatch(regExp);
+ });
+
+ it('should create a RegExp from a string', () => {
+ expect(createRegExpForWords('.')?.toString()).toEqual('/./i');
+ });
+ });
+});
diff --git a/tests/utils.ts b/tests/utils.ts
deleted file mode 100644
index d4129b2a..00000000
--- a/tests/utils.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license Use of this source code is governed by an MIT-style license that
- * can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-rxjs
- */
-
-import { createRuleTester } from "eslint-etc";
-import { resolve } from "path";
-
-export const ruleTester = createRuleTester({
- filename: resolve("./tests/file.tsx"),
-});
diff --git a/tsconfig-dist.json b/tsconfig-dist.json
deleted file mode 100644
index 24a9e62f..00000000
--- a/tsconfig-dist.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "compilerOptions": {
- "outDir": "dist"
- },
- "extends": "./tsconfig.json",
- "include": [
- "source/**/*.ts"
- ]
-}
diff --git a/tsconfig.json b/tsconfig.json
index c69f7983..69f294a5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,24 +1,37 @@
{
"compilerOptions": {
- "baseUrl": ".",
- "declaration": false,
+ /* Imports */
+ "target": "ES2018",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
"esModuleInterop": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+
+ /* Globals */
+ "lib": [
+ "ESNext",
+ ],
+ "types": [
+ "vitest/globals",
+ ],
+
+ /* Output */
+ "noEmit": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
"importHelpers": true,
- "lib": ["esnext"],
- "module": "commonjs",
- "moduleResolution": "node",
- "noEmitHelpers": true,
- "outDir": "build",
- "paths": {},
- "removeComments": true,
+
+ /* Rules */
"skipLibCheck": true,
- "sourceMap": false,
"strict": true,
- "target": "es2018"
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitOverride": true,
},
- "exclude": [],
"include": [
- "source/**/*.ts",
- "tests/**/*.ts"
- ]
+ "src",
+ "tests",
+ ],
}
diff --git a/tsup.config.ts b/tsup.config.ts
new file mode 100644
index 00000000..adb16907
--- /dev/null
+++ b/tsup.config.ts
@@ -0,0 +1,12 @@
+import { defineConfig } from 'tsup';
+
+export default defineConfig({
+ entry: [
+ 'src/index.ts',
+ ],
+ clean: true,
+ dts: true,
+ cjsInterop: true,
+ splitting: true,
+ format: ['cjs', 'esm'],
+});
diff --git a/vitest.config.mts b/vitest.config.mts
new file mode 100644
index 00000000..188f2081
--- /dev/null
+++ b/vitest.config.mts
@@ -0,0 +1,12 @@
+import { defineConfig, coverageConfigDefaults } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ globals: true,
+ reporters: process.env.GITHUB_ACTIONS ? ['dot', 'github-actions'] : ['dot'],
+ coverage: {
+ reporter: ['text-summary', 'lcovonly'],
+ exclude: ['scripts/**', ...coverageConfigDefaults.exclude],
+ },
+ },
+});
diff --git a/yarn.lock b/yarn.lock
index 663e7452..6bd0400b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1,2482 +1,4790 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@babel/code-frame@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
- integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
- dependencies:
- "@babel/highlight" "^7.18.6"
-
-"@babel/generator@^7.18.7":
- version "7.18.7"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd"
- integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==
- dependencies:
- "@babel/types" "^7.18.7"
- "@jridgewell/gen-mapping" "^0.3.2"
- jsesc "^2.5.1"
-
-"@babel/helper-environment-visitor@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7"
- integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==
-
-"@babel/helper-function-name@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz#8334fecb0afba66e6d87a7e8c6bb7fed79926b83"
- integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==
- dependencies:
- "@babel/template" "^7.18.6"
- "@babel/types" "^7.18.6"
-
-"@babel/helper-hoist-variables@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
- integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-split-export-declaration@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
- integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
- dependencies:
- "@babel/types" "^7.18.6"
-
-"@babel/helper-validator-identifier@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
- integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
-
-"@babel/highlight@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
- integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
- dependencies:
- "@babel/helper-validator-identifier" "^7.18.6"
- chalk "^2.0.0"
- js-tokens "^4.0.0"
-
-"@babel/parser@^7.10.3", "@babel/parser@^7.18.6", "@babel/parser@^7.18.8":
- version "7.18.8"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf"
- integrity sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==
-
-"@babel/template@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
- integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/parser" "^7.18.6"
- "@babel/types" "^7.18.6"
-
-"@babel/traverse@^7.10.3":
- version "7.18.8"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.8.tgz#f095e62ab46abf1da35e5a2011f43aee72d8d5b0"
- integrity sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/generator" "^7.18.7"
- "@babel/helper-environment-visitor" "^7.18.6"
- "@babel/helper-function-name" "^7.18.6"
- "@babel/helper-hoist-variables" "^7.18.6"
- "@babel/helper-split-export-declaration" "^7.18.6"
- "@babel/parser" "^7.18.8"
- "@babel/types" "^7.18.8"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/types@^7.10.3", "@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.18.8":
- version "7.18.8"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f"
- integrity sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==
- dependencies:
- "@babel/helper-validator-identifier" "^7.18.6"
- to-fast-properties "^2.0.0"
-
-"@cartant/eslint-config@^3.0.0":
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/@cartant/eslint-config/-/eslint-config-3.0.1.tgz#7b46e7d099395286b42931cfbab77ef0b30c84ad"
- integrity sha512-4wgtm5+9dKI0cg2O5MKL1jmecHlZVVJg96uVtn9IaCpr1qi/ovFnUMAc9Jejz+TPfFmOSPSf4cG/9PSJRuiFpw==
- dependencies:
- "@typescript-eslint/eslint-plugin" "^5.0.0"
- eslint-plugin-import "^2.20.2"
-
-"@cspotcode/source-map-support@^0.8.0":
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
- integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
- dependencies:
- "@jridgewell/trace-mapping" "0.3.9"
-
-"@eslint/eslintrc@^1.3.0":
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
- integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==
- dependencies:
- ajv "^6.12.4"
- debug "^4.3.2"
- espree "^9.3.2"
- globals "^13.15.0"
- ignore "^5.2.0"
- import-fresh "^3.2.1"
- js-yaml "^4.1.0"
- minimatch "^3.1.2"
- strip-json-comments "^3.1.1"
-
-"@humanwhocodes/config-array@^0.9.2":
- version "0.9.5"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
- integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==
- dependencies:
- "@humanwhocodes/object-schema" "^1.2.1"
- debug "^4.1.1"
- minimatch "^3.0.4"
-
-"@humanwhocodes/object-schema@^1.2.1":
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
- integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
-
-"@jridgewell/gen-mapping@^0.3.2":
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
- integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
- dependencies:
- "@jridgewell/set-array" "^1.0.1"
- "@jridgewell/sourcemap-codec" "^1.4.10"
- "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/resolve-uri@^3.0.3":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
- integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
-
-"@jridgewell/set-array@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
- integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-
-"@jridgewell/sourcemap-codec@^1.4.10":
- version "1.4.14"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
- integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
-
-"@jridgewell/trace-mapping@0.3.9":
- version "0.3.9"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
- integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
- dependencies:
- "@jridgewell/resolve-uri" "^3.0.3"
- "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@jridgewell/trace-mapping@^0.3.9":
- version "0.3.14"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
- integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
- dependencies:
- "@jridgewell/resolve-uri" "^3.0.3"
- "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@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"
-
-"@tsconfig/node10@^1.0.7":
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
- integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
-
-"@tsconfig/node12@^1.0.7":
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
- integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
-
-"@tsconfig/node14@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
- integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
-
-"@tsconfig/node16@^1.0.2":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
- integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
-
-"@types/chai@^4.2.0":
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.1.tgz#e2c6e73e0bdeb2521d00756d099218e9f5d90a04"
- integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==
-
-"@types/common-tags@^1.8.0":
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/@types/common-tags/-/common-tags-1.8.1.tgz#a5a49ca5ebbb58e0f8947f3ec98950c8970a68a9"
- integrity sha512-20R/mDpKSPWdJs5TOpz3e7zqbeCNuMCPhV7Yndk9KU2Rbij2r5W4RzwDPkzC+2lzUqXYu9rFzTktCBnDjHuNQg==
-
-"@types/eslint@^8.0.0":
- version "8.4.5"
- resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4"
- integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==
- dependencies:
- "@types/estree" "*"
- "@types/json-schema" "*"
-
-"@types/estree@*":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
- integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
-
-"@types/json-schema@*", "@types/json-schema@^7.0.9":
- version "7.0.11"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
- integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
-
-"@types/json5@^0.0.29":
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
- integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-
-"@types/mocha@^9.0.0":
- version "9.1.1"
- resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
- integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
-
-"@types/node@^18.0.0":
- version "18.0.5"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.5.tgz#96be8113b014e9e7f0c3609c4a25afadd85ff659"
- integrity sha512-En7tneq+j0qAiVwysBD79y86MT3ModuoIJbe7JXp+sb5UAjInSShmK3nXXMioBzfF7rXC12hv12d4IyCVwN4dA==
-
-"@types/yargs-parser@*":
- version "21.0.0"
- resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
- integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==
-
-"@types/yargs@^17.0.0":
- version "17.0.10"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a"
- integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==
- dependencies:
- "@types/yargs-parser" "*"
-
-"@typescript-eslint/eslint-plugin@^5.0.0":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359"
- integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==
- dependencies:
- "@typescript-eslint/scope-manager" "5.30.6"
- "@typescript-eslint/type-utils" "5.30.6"
- "@typescript-eslint/utils" "5.30.6"
- debug "^4.3.4"
- functional-red-black-tree "^1.0.1"
- ignore "^5.2.0"
- regexpp "^3.2.0"
- semver "^7.3.7"
- tsutils "^3.21.0"
-
-"@typescript-eslint/experimental-utils@^5.0.0":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.30.6.tgz#fe30d2800aedcad7465d9260b66068337df71612"
- integrity sha512-bqvT+0L8IjtW7MCrMgm9oVNxs4g7mESro1mm5c1/SNfTnHuFTf9OUX1WzVkTz75M9cp//UrTrSmGvK48NEKshQ==
- dependencies:
- "@typescript-eslint/utils" "5.30.6"
-
-"@typescript-eslint/parser@^5.0.0":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92"
- integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==
- dependencies:
- "@typescript-eslint/scope-manager" "5.30.6"
- "@typescript-eslint/types" "5.30.6"
- "@typescript-eslint/typescript-estree" "5.30.6"
- debug "^4.3.4"
-
-"@typescript-eslint/scope-manager@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33"
- integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==
- dependencies:
- "@typescript-eslint/types" "5.30.6"
- "@typescript-eslint/visitor-keys" "5.30.6"
-
-"@typescript-eslint/type-utils@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af"
- integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==
- dependencies:
- "@typescript-eslint/utils" "5.30.6"
- debug "^4.3.4"
- tsutils "^3.21.0"
-
-"@typescript-eslint/types@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1"
- integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==
-
-"@typescript-eslint/typescript-estree@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e"
- integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==
- dependencies:
- "@typescript-eslint/types" "5.30.6"
- "@typescript-eslint/visitor-keys" "5.30.6"
- debug "^4.3.4"
- globby "^11.1.0"
- is-glob "^4.0.3"
- semver "^7.3.7"
- tsutils "^3.21.0"
-
-"@typescript-eslint/utils@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc"
- integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==
- dependencies:
- "@types/json-schema" "^7.0.9"
- "@typescript-eslint/scope-manager" "5.30.6"
- "@typescript-eslint/types" "5.30.6"
- "@typescript-eslint/typescript-estree" "5.30.6"
- eslint-scope "^5.1.1"
- eslint-utils "^3.0.0"
-
-"@typescript-eslint/visitor-keys@5.30.6":
- version "5.30.6"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c"
- integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==
- dependencies:
- "@typescript-eslint/types" "5.30.6"
- eslint-visitor-keys "^3.3.0"
-
-"@ungap/promise-all-settled@1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
- integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
-
-acorn-jsx@^5.3.2:
- version "5.3.2"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
- integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-
-acorn-walk@^8.1.1:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
- integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
-
-acorn@^8.4.1, acorn@^8.7.1:
- version "8.7.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
- integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
-
-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@^6.10.0, ajv@^6.12.4:
- version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
- integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
- dependencies:
- fast-deep-equal "^3.1.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
- uri-js "^4.2.2"
-
-ansi-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.3.0:
- 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-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-regex@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
- integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
-
-ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.0.0, ansi-styles@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
- integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
- dependencies:
- color-convert "^2.0.1"
-
-ansi-styles@^6.0.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3"
- integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==
-
-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"
-
-arg@^4.1.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
- integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
-
-argparse@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
- integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-
-array-includes@^3.1.4:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
- integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
- get-intrinsic "^1.1.1"
- is-string "^1.0.7"
-
-array-union@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
- integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
-array.prototype.flat@^1.2.5:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b"
- integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.2"
- es-shim-unscopables "^1.0.0"
-
-assertion-error@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
- integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
-
-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==
-
-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==
-
-bent@~7.3.6:
- version "7.3.12"
- resolved "https://registry.yarnpkg.com/bent/-/bent-7.3.12.tgz#e0a2775d4425e7674c64b78b242af4f49da6b035"
- integrity sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==
- dependencies:
- bytesish "^0.4.1"
- caseless "~0.12.0"
- is-stream "^2.0.0"
-
-binary-extensions@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
- integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
-
-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@^3.0.2, 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"
-
-browser-stdout@1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
- integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
-
-bytesish@^0.4.1:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/bytesish/-/bytesish-0.4.4.tgz#f3b535a0f1153747427aee27256748cff92347e6"
- integrity sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==
-
-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"
-
-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==
-
-camelcase@^6.0.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
- integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-
-caseless@~0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
- integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
-
-chai@^4.2.0:
- version "4.3.6"
- resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c"
- integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==
- dependencies:
- assertion-error "^1.1.0"
- check-error "^1.0.2"
- deep-eql "^3.0.1"
- get-func-name "^2.0.0"
- loupe "^2.3.1"
- pathval "^1.1.1"
- type-detect "^4.0.5"
-
-chalk@^2.0.0:
- 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, chalk@^4.1.0, chalk@~4.1.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"
-
-check-error@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
- integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
-
-chokidar@3.5.3:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
- integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
- 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"
-
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
-cli-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
- integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
- dependencies:
- restore-cursor "^3.1.0"
-
-cli-truncate@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
- integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
- dependencies:
- slice-ansi "^3.0.0"
- string-width "^4.2.0"
-
-cli-truncate@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389"
- integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==
- dependencies:
- slice-ansi "^5.0.0"
- string-width "^5.0.0"
-
-cliui@^7.0.2:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
- integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
- dependencies:
- string-width "^4.2.0"
- strip-ansi "^6.0.0"
- wrap-ansi "^7.0.0"
-
-color-convert@^1.9.0:
- 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 sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-
-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==
-
-colorette@^2.0.16, colorette@^2.0.17:
- version "2.0.19"
- resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
- integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
-
-commander@^9.3.0:
- version "9.4.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
- integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
-
-common-tags@^1.8.0:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6"
- integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-
-create-require@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
- integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
-
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
- integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-debug@4.3.3:
- version "4.3.3"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
- integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
- dependencies:
- ms "2.1.2"
-
-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@^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"
-
-debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
- dependencies:
- ms "2.1.2"
-
-decamelize@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
- integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
-
-decamelize@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9"
- integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==
-
-deep-eql@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
- integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
- dependencies:
- type-detect "^4.0.0"
-
-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==
-
-define-properties@^1.1.3, define-properties@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
- integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
- dependencies:
- has-property-descriptors "^1.0.0"
- object-keys "^1.1.1"
-
-diff@5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
- integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
-
-diff@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
- integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-
-dir-glob@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
- integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
- dependencies:
- path-type "^4.0.0"
-
-doctrine@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
- integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
- dependencies:
- esutils "^2.0.2"
-
-doctrine@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
- integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
- dependencies:
- esutils "^2.0.2"
-
-eastasianwidth@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
- integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
-
-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.2.2:
- version "9.2.2"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
- integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
-
-es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
- version "1.20.1"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
- integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
- dependencies:
- call-bind "^1.0.2"
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- function.prototype.name "^1.1.5"
- get-intrinsic "^1.1.1"
- get-symbol-description "^1.0.0"
- has "^1.0.3"
- has-property-descriptors "^1.0.0"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- is-callable "^1.2.4"
- is-negative-zero "^2.0.2"
- is-regex "^1.1.4"
- is-shared-array-buffer "^1.0.2"
- is-string "^1.0.7"
- is-weakref "^1.0.2"
- object-inspect "^1.12.0"
- object-keys "^1.1.1"
- object.assign "^4.1.2"
- regexp.prototype.flags "^1.4.3"
- string.prototype.trimend "^1.0.5"
- string.prototype.trimstart "^1.0.5"
- unbox-primitive "^1.0.2"
-
-es-shim-unscopables@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
- integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
- dependencies:
- has "^1.0.3"
-
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.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-string-regexp@4.0.0, 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==
-
-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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
-
-eslint-etc@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/eslint-etc/-/eslint-etc-5.2.0.tgz#c51c19a2ffb6447af76a1c5ffd13b9a212db859b"
- integrity sha512-Gcm/NMa349FOXb1PEEfNMMyIANuorIc2/mI5Vfu1zENNsz+FBVhF62uY6gPUCigm/xDOc8JOnl+71WGnlzlDag==
- dependencies:
- "@typescript-eslint/experimental-utils" "^5.0.0"
- tsutils "^3.17.1"
- tsutils-etc "^1.4.1"
-
-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.7.3:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
- integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
- dependencies:
- debug "^3.2.7"
- find-up "^2.1.0"
-
-eslint-plugin-import@^2.20.2:
- version "2.26.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
- integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
- dependencies:
- array-includes "^3.1.4"
- array.prototype.flat "^1.2.5"
- debug "^2.6.9"
- doctrine "^2.1.0"
- eslint-import-resolver-node "^0.3.6"
- eslint-module-utils "^2.7.3"
- has "^1.0.3"
- is-core-module "^2.8.1"
- is-glob "^4.0.3"
- minimatch "^3.1.2"
- object.values "^1.1.5"
- resolve "^1.22.0"
- tsconfig-paths "^3.14.1"
-
-eslint-scope@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
- integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
- dependencies:
- esrecurse "^4.3.0"
- estraverse "^4.1.1"
-
-eslint-scope@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
- integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
- dependencies:
- esrecurse "^4.3.0"
- estraverse "^5.2.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@^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-visitor-keys@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
- integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-
-eslint@^8.0.0:
- version "8.20.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b"
- integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==
- dependencies:
- "@eslint/eslintrc" "^1.3.0"
- "@humanwhocodes/config-array" "^0.9.2"
- ajv "^6.10.0"
- chalk "^4.0.0"
- cross-spawn "^7.0.2"
- debug "^4.3.2"
- doctrine "^3.0.0"
- escape-string-regexp "^4.0.0"
- eslint-scope "^7.1.1"
- eslint-utils "^3.0.0"
- eslint-visitor-keys "^3.3.0"
- espree "^9.3.2"
- esquery "^1.4.0"
- esutils "^2.0.2"
- fast-deep-equal "^3.1.3"
- file-entry-cache "^6.0.1"
- functional-red-black-tree "^1.0.1"
- glob-parent "^6.0.1"
- globals "^13.15.0"
- ignore "^5.2.0"
- import-fresh "^3.0.0"
- imurmurhash "^0.1.4"
- is-glob "^4.0.0"
- js-yaml "^4.1.0"
- json-stable-stringify-without-jsonify "^1.0.1"
- levn "^0.4.1"
- lodash.merge "^4.6.2"
- minimatch "^3.1.2"
- natural-compare "^1.4.0"
- optionator "^0.9.1"
- regexpp "^3.2.0"
- strip-ansi "^6.0.1"
- strip-json-comments "^3.1.0"
- text-table "^0.2.0"
- v8-compile-cache "^2.0.3"
-
-espree@^9.3.2:
- version "9.3.2"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596"
- integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==
- dependencies:
- acorn "^8.7.1"
- acorn-jsx "^5.3.2"
- eslint-visitor-keys "^3.3.0"
-
-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.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.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
- integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
-
-esutils@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
- integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-
-execa@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20"
- integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==
- dependencies:
- cross-spawn "^7.0.3"
- get-stream "^6.0.1"
- human-signals "^3.0.1"
- is-stream "^3.0.0"
- merge-stream "^2.0.0"
- npm-run-path "^5.1.0"
- onetime "^6.0.0"
- signal-exit "^3.0.7"
- strip-final-newline "^3.0.0"
-
-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.2.9:
- version "3.2.11"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
- integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
- dependencies:
- "@nodelib/fs.stat" "^2.0.2"
- "@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.2"
- merge2 "^1.3.0"
- micromatch "^4.0.4"
-
-fast-json-stable-stringify@^2.0.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:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
- integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
-
-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"
-
-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"
-
-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"
-
-find-up@5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
- integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
- dependencies:
- locate-path "^6.0.0"
- path-exists "^4.0.0"
-
-find-up@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==
- dependencies:
- locate-path "^2.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"
-
-flat@^5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
- integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
-
-flatted@^3.1.0:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2"
- integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-
-fsevents@~2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
- integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-function.prototype.name@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
- integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
- functions-have-names "^1.2.2"
-
-functional-red-black-tree@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
- integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
-
-functions-have-names@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
- integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
-
-get-caller-file@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
- integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-
-get-func-name@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
- integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
-
-get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
- integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.3"
-
-get-stream@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
- integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
-
-get-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"
-
-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-parent@^6.0.1:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
- integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
- dependencies:
- is-glob "^4.0.3"
-
-glob@7.2.0:
- 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"
-
-glob@^7.1.3, glob@~7.2.0:
- version "7.2.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
- integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.1.1"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-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.15.0:
- version "13.16.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a"
- integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==
- dependencies:
- type-fest "^0.20.2"
-
-globby@^11.1.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
- integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.2.9"
- ignore "^5.2.0"
- merge2 "^1.4.1"
- slash "^3.0.0"
-
-growl@1.10.5:
- version "1.10.5"
- resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
- integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
-
-has-bigints@^1.0.1, has-bigints@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
- integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
-
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-property-descriptors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
- integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
- dependencies:
- get-intrinsic "^1.1.1"
-
-has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
- integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
-
-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@^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"
-
-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==
-
-human-signals@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5"
- integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==
-
-husky@^8.0.0:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9"
- integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==
-
-ignore@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
- integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
-
-import-fresh@^3.0.0, import-fresh@^3.2.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
- integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-imurmurhash@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
- 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==
-
-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"
-
-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@~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-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-core-module@^2.8.1, is-core-module@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
- integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
- dependencies:
- has "^1.0.3"
-
-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-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-fullwidth-code-point@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88"
- integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==
-
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
- integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-negative-zero@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
- integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
-
-is-number-object@^1.0.4:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
- integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
- dependencies:
- has-tostringtag "^1.0.0"
-
-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-plain-obj@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
- integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
-
-is-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-shared-array-buffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
- integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
- dependencies:
- call-bind "^1.0.2"
-
-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-stream@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
- integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
-
-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-unicode-supported@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
- integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
-
-is-weakref@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
- integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
- dependencies:
- call-bind "^1.0.2"
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
-
-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@4.1.0, js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
- dependencies:
- argparse "^2.0.1"
-
-jsesc@^2.5.1:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
- integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-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-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 sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-
-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"
-
-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==
-
-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"
-
-lilconfig@2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
- integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
-
-lint-staged@^13.0.0:
- version "13.0.3"
- resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.0.3.tgz#d7cdf03a3830b327a2b63c6aec953d71d9dc48c6"
- integrity sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==
- dependencies:
- cli-truncate "^3.1.0"
- colorette "^2.0.17"
- commander "^9.3.0"
- debug "^4.3.4"
- execa "^6.1.0"
- lilconfig "2.0.5"
- listr2 "^4.0.5"
- micromatch "^4.0.5"
- normalize-path "^3.0.0"
- object-inspect "^1.12.2"
- pidtree "^0.6.0"
- string-argv "^0.3.1"
- yaml "^2.1.1"
-
-listr2@^4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5"
- integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==
- dependencies:
- cli-truncate "^2.1.0"
- colorette "^2.0.16"
- log-update "^4.0.0"
- p-map "^4.0.0"
- rfdc "^1.3.0"
- rxjs "^7.5.5"
- through "^2.3.8"
- wrap-ansi "^7.0.0"
-
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
-locate-path@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
- integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
- dependencies:
- p-locate "^5.0.0"
-
-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==
-
-log-symbols@4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
- integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
- dependencies:
- chalk "^4.1.0"
- is-unicode-supported "^0.1.0"
-
-log-update@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
- integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==
- dependencies:
- ansi-escapes "^4.3.0"
- cli-cursor "^3.1.0"
- slice-ansi "^4.0.0"
- wrap-ansi "^6.2.0"
-
-loupe@^2.3.1:
- version "2.3.4"
- resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3"
- integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==
- dependencies:
- get-func-name "^2.0.0"
-
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-make-error@^1.1.1:
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
- integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
-
-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, merge2@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
- integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-
-micromatch@^4.0.4, micromatch@^4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
- integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
- dependencies:
- braces "^3.0.2"
- picomatch "^2.3.1"
-
-mimic-fn@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
- integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-
-mimic-fn@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
- integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
-
-minimatch@4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4"
- integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
- integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.0, minimist@^1.2.6:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-
-mocha@^9.0.0:
- version "9.2.2"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9"
- integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
- dependencies:
- "@ungap/promise-all-settled" "1.1.2"
- ansi-colors "4.1.1"
- browser-stdout "1.3.1"
- chokidar "3.5.3"
- debug "4.3.3"
- diff "5.0.0"
- escape-string-regexp "4.0.0"
- find-up "5.0.0"
- glob "7.2.0"
- growl "1.10.5"
- he "1.2.0"
- js-yaml "4.1.0"
- log-symbols "4.1.0"
- minimatch "4.2.1"
- ms "2.1.3"
- nanoid "3.3.1"
- serialize-javascript "6.0.0"
- strip-json-comments "3.1.1"
- supports-color "8.1.1"
- which "2.0.2"
- workerpool "6.2.0"
- yargs "16.2.0"
- yargs-parser "20.2.4"
- yargs-unparser "2.0.0"
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-
-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.3, 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==
-
-nanoid@3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
- integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
-
-natural-compare@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
- integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
-
-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==
-
-npm-run-path@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00"
- integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==
- dependencies:
- path-key "^4.0.0"
-
-object-inspect@^1.12.0, object-inspect@^1.12.2, object-inspect@^1.9.0:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
- integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
-
-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.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.values@^1.1.5:
- 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"
-
-once@^1.3.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
- 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"
-
-onetime@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
- integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
- dependencies:
- mimic-fn "^4.0.0"
-
-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"
-
-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@^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 sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==
- dependencies:
- p-limit "^1.1.0"
-
-p-locate@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
- integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
- dependencies:
- p-limit "^3.0.2"
-
-p-map@^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-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==
-
-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"
-
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==
-
-path-exists@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
- 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 sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-
-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-key@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
- integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
-
-path-parse@^1.0.7:
- 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-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==
-
-pathval@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
- integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
-
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
- integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-pidtree@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
- integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
-
-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==
-
-prettier@^2.0.0:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
- integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
-
-prompts@~2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
- integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
- dependencies:
- kleur "^3.0.3"
- sisteransi "^1.0.5"
-
-punycode@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
- integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-
-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==
-
-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"
-
-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"
-
-regexp.prototype.flags@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
- integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- functions-have-names "^1.2.2"
-
-regexpp@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
- integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
-
-require-directory@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
-
-requireindex@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef"
- integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==
-
-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@^1.20.0, resolve@^1.22.0:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-restore-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
- integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
- dependencies:
- onetime "^5.1.0"
- signal-exit "^3.0.2"
-
-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==
-
-rfdc@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
- integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
-
-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"
-
-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"
-
-rxjs-report-usage@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/rxjs-report-usage/-/rxjs-report-usage-1.0.6.tgz#6e06034d9e1592e8a45bee877631638e4bac2576"
- integrity sha512-omv1DIv5z1kV+zDAEjaDjWSkx8w5TbFp5NZoPwUipwzYVcor/4So9ZU3bUyQ1c8lxY5Q0Es/ztWW7PGjY7to0Q==
- dependencies:
- "@babel/parser" "^7.10.3"
- "@babel/traverse" "^7.10.3"
- "@babel/types" "^7.10.3"
- bent "~7.3.6"
- chalk "~4.1.0"
- glob "~7.2.0"
- prompts "~2.4.2"
-
-rxjs@^7.0.0, rxjs@^7.5.5:
- version "7.5.6"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc"
- integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==
- dependencies:
- tslib "^2.1.0"
-
-safe-buffer@^5.1.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==
-
-semver@^7.3.7:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
- dependencies:
- lru-cache "^6.0.0"
-
-serialize-javascript@6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
- integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
- dependencies:
- randombytes "^2.1.0"
-
-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@^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==
-
-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.2, signal-exit@^3.0.7:
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
- integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
-
-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@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
- integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==
- dependencies:
- ansi-styles "^4.0.0"
- astral-regex "^2.0.0"
- is-fullwidth-code-point "^3.0.0"
-
-slice-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
- integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
- dependencies:
- ansi-styles "^4.0.0"
- astral-regex "^2.0.0"
- is-fullwidth-code-point "^3.0.0"
-
-slice-ansi@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a"
- integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==
- dependencies:
- ansi-styles "^6.0.0"
- is-fullwidth-code-point "^4.0.0"
-
-string-argv@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
- integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==
-
-string-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-width@^5.0.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
- integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
- dependencies:
- eastasianwidth "^0.2.0"
- emoji-regex "^9.2.2"
- strip-ansi "^7.0.1"
-
-string.prototype.trimend@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
- integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-string.prototype.trimstart@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
- integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-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-ansi@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
- integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==
- dependencies:
- ansi-regex "^6.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 sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
-
-strip-final-newline@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
- integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
-
-strip-json-comments@3.1.1, 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==
-
-supports-color@8.1.1:
- version "8.1.1"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
- integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
- dependencies:
- has-flag "^4.0.0"
-
-supports-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@^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-preserve-symlinks-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
- integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-text-table@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
- integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
-
-through@^2.3.8:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
- integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
-
-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 sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
-
-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"
-
-ts-node@^10.0.0:
- version "10.9.1"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
- integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
- dependencies:
- "@cspotcode/source-map-support" "^0.8.0"
- "@tsconfig/node10" "^1.0.7"
- "@tsconfig/node12" "^1.0.7"
- "@tsconfig/node14" "^1.0.0"
- "@tsconfig/node16" "^1.0.2"
- acorn "^8.4.1"
- acorn-walk "^8.1.1"
- arg "^4.1.0"
- create-require "^1.1.0"
- diff "^4.0.1"
- make-error "^1.1.1"
- v8-compile-cache-lib "^3.0.1"
- yn "3.1.1"
-
-tsconfig-paths@^3.14.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
- integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
- dependencies:
- "@types/json5" "^0.0.29"
- json5 "^1.0.1"
- minimist "^1.2.6"
- strip-bom "^3.0.0"
-
-tslib@^1.8.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
- integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-
-tslib@^2.0.0, tslib@^2.1.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
- integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
-
-tsutils-etc@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/tsutils-etc/-/tsutils-etc-1.4.1.tgz#bd42a0079d534765ab314d087f8a89c77a68723f"
- integrity sha512-6UPYgc7OXcIW5tFxlsZF3OVSBvDInl/BkS3Xsu64YITXk7WrnWTVByKWPCThFDBp5gl5IGHOzGMdQuDCE7OL4g==
- dependencies:
- "@types/yargs" "^17.0.0"
- yargs "^17.0.0"
-
-tsutils@^3.0.0, 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"
-
-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-detect@^4.0.0, type-detect@^4.0.5:
- 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==
-
-typescript@~4.7.4:
- version "4.7.4"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
- integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
-
-unbox-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
- integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
- dependencies:
- call-bind "^1.0.2"
- has-bigints "^1.0.2"
- has-symbols "^1.0.3"
- which-boxed-primitive "^1.0.2"
-
-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"
-
-v8-compile-cache-lib@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
- integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
-
-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==
-
-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@2.0.2, which@^2.0.1:
- 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:
- 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==
-
-workerpool@6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
- integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
-
-wrap-ansi@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
- integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-
-y18n@^5.0.5:
- version "5.0.8"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
- integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
-
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
-yaml@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
- integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
-
-yargs-parser@20.2.4:
- version "20.2.4"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
- integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
-
-yargs-parser@^20.2.2:
- version "20.2.9"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
- integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
-
-yargs-parser@^21.0.0:
- version "21.0.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35"
- integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==
-
-yargs-unparser@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
- integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
- dependencies:
- camelcase "^6.0.0"
- decamelize "^4.0.0"
- flat "^5.0.2"
- is-plain-obj "^2.1.0"
-
-yargs@16.2.0:
- version "16.2.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
- integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
- dependencies:
- cliui "^7.0.2"
- escalade "^3.1.1"
- get-caller-file "^2.0.5"
- require-directory "^2.1.1"
- string-width "^4.2.0"
- y18n "^5.0.5"
- yargs-parser "^20.2.2"
-
-yargs@^17.0.0:
- version "17.5.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
- integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
- dependencies:
- cliui "^7.0.2"
- escalade "^3.1.1"
- get-caller-file "^2.0.5"
- require-directory "^2.1.1"
- string-width "^4.2.3"
- y18n "^5.0.5"
- yargs-parser "^21.0.0"
-
-yn@3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
- integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
-
-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==
+# This file is generated by running "yarn install" inside your project.
+# Manual changes might be lost - proceed with caution!
+
+__metadata:
+ version: 8
+ cacheKey: 10c0
+
+"@ampproject/remapping@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "@ampproject/remapping@npm:2.3.0"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.5"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed
+ languageName: node
+ linkType: hard
+
+"@babel/code-frame@npm:^7.0.0":
+ version: 7.26.2
+ resolution: "@babel/code-frame@npm:7.26.2"
+ dependencies:
+ "@babel/helper-validator-identifier": "npm:^7.25.9"
+ js-tokens: "npm:^4.0.0"
+ picocolors: "npm:^1.0.0"
+ checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8
+ languageName: node
+ linkType: hard
+
+"@babel/helper-string-parser@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-string-parser@npm:7.25.9"
+ checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6
+ languageName: node
+ linkType: hard
+
+"@babel/helper-validator-identifier@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-validator-identifier@npm:7.25.9"
+ checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d
+ languageName: node
+ linkType: hard
+
+"@babel/parser@npm:^7.25.4":
+ version: 7.26.2
+ resolution: "@babel/parser@npm:7.26.2"
+ dependencies:
+ "@babel/types": "npm:^7.26.0"
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: 10c0/751a743087b3a9172a7599f1421830d44c38f065ef781588d2bfb1c98f9b461719a226feb13c868d7a284783eee120c88ea522593118f2668f46ebfb1105c4d7
+ languageName: node
+ linkType: hard
+
+"@babel/types@npm:^7.25.4, @babel/types@npm:^7.26.0":
+ version: 7.26.0
+ resolution: "@babel/types@npm:7.26.0"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.25.9"
+ "@babel/helper-validator-identifier": "npm:^7.25.9"
+ checksum: 10c0/b694f41ad1597127e16024d766c33a641508aad037abd08d0d1f73af753e1119fa03b4a107d04b5f92cc19c095a594660547ae9bead1db2299212d644b0a5cb8
+ languageName: node
+ linkType: hard
+
+"@bcoe/v8-coverage@npm:^0.2.3":
+ version: 0.2.3
+ resolution: "@bcoe/v8-coverage@npm:0.2.3"
+ checksum: 10c0/6b80ae4cb3db53f486da2dc63b6e190a74c8c3cca16bb2733f234a0b6a9382b09b146488ae08e2b22cf00f6c83e20f3e040a2f7894f05c045c946d6a090b1d52
+ languageName: node
+ linkType: hard
+
+"@esbuild/aix-ppc64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/aix-ppc64@npm:0.21.5"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/aix-ppc64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/aix-ppc64@npm:0.24.0"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/android-arm64@npm:0.21.5"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-arm64@npm:0.24.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/android-arm@npm:0.21.5"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-arm@npm:0.24.0"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/android-x64@npm:0.21.5"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-x64@npm:0.24.0"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-arm64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/darwin-arm64@npm:0.21.5"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/darwin-arm64@npm:0.24.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/darwin-x64@npm:0.21.5"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/darwin-x64@npm:0.24.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-arm64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/freebsd-arm64@npm:0.21.5"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/freebsd-arm64@npm:0.24.0"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/freebsd-x64@npm:0.21.5"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/freebsd-x64@npm:0.24.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-arm64@npm:0.21.5"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-arm64@npm:0.24.0"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-arm@npm:0.21.5"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-arm@npm:0.24.0"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ia32@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-ia32@npm:0.21.5"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ia32@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-ia32@npm:0.24.0"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-loong64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-loong64@npm:0.21.5"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-loong64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-loong64@npm:0.24.0"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-mips64el@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-mips64el@npm:0.21.5"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-mips64el@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-mips64el@npm:0.24.0"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ppc64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-ppc64@npm:0.21.5"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ppc64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-ppc64@npm:0.24.0"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-riscv64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-riscv64@npm:0.21.5"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-riscv64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-riscv64@npm:0.24.0"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-s390x@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-s390x@npm:0.21.5"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-s390x@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-s390x@npm:0.24.0"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/linux-x64@npm:0.21.5"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-x64@npm:0.24.0"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/netbsd-x64@npm:0.21.5"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/netbsd-x64@npm:0.24.0"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/openbsd-arm64@npm:0.24.0"
+ conditions: os=openbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/openbsd-x64@npm:0.21.5"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/openbsd-x64@npm:0.24.0"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/sunos-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/sunos-x64@npm:0.21.5"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/sunos-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/sunos-x64@npm:0.24.0"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-arm64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/win32-arm64@npm:0.21.5"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-arm64@npm:0.24.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-ia32@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/win32-ia32@npm:0.21.5"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-ia32@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-ia32@npm:0.24.0"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-x64@npm:0.21.5":
+ version: 0.21.5
+ resolution: "@esbuild/win32-x64@npm:0.21.5"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-x64@npm:0.24.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.4.1":
+ version: 4.4.1
+ resolution: "@eslint-community/eslint-utils@npm:4.4.1"
+ dependencies:
+ eslint-visitor-keys: "npm:^3.4.3"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ checksum: 10c0/2aa0ac2fc50ff3f234408b10900ed4f1a0b19352f21346ad4cc3d83a1271481bdda11097baa45d484dd564c895e0762a27a8240be7a256b3ad47129e96528252
+ languageName: node
+ linkType: hard
+
+"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.11.0, @eslint-community/regexpp@npm:^4.12.1":
+ version: 4.12.1
+ resolution: "@eslint-community/regexpp@npm:4.12.1"
+ checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6
+ languageName: node
+ linkType: hard
+
+"@eslint/compat@npm:^1.1.1":
+ version: 1.2.2
+ resolution: "@eslint/compat@npm:1.2.2"
+ peerDependencies:
+ eslint: ^9.10.0
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10c0/c19e1765673520daf6f08bb82f957c6b42079389725ceda99a4387c403fccd5f9a99d142feec43ed032cb240038ea67db9748b17bf8de4ceb8b2fba382089780
+ languageName: node
+ linkType: hard
+
+"@eslint/config-array@npm:^0.19.0":
+ version: 0.19.0
+ resolution: "@eslint/config-array@npm:0.19.0"
+ dependencies:
+ "@eslint/object-schema": "npm:^2.1.4"
+ debug: "npm:^4.3.1"
+ minimatch: "npm:^3.1.2"
+ checksum: 10c0/def23c6c67a8f98dc88f1b87e17a5668e5028f5ab9459661aabfe08e08f2acd557474bbaf9ba227be0921ae4db232c62773dbb7739815f8415678eb8f592dbf5
+ languageName: node
+ linkType: hard
+
+"@eslint/core@npm:^0.9.0":
+ version: 0.9.0
+ resolution: "@eslint/core@npm:0.9.0"
+ checksum: 10c0/6d8e8e0991cef12314c49425d8d2d9394f5fb1a36753ff82df7c03185a4646cb7c8736cf26638a4a714782cedf4b23cfc17667d282d3e5965b3920a0e7ce20d4
+ languageName: node
+ linkType: hard
+
+"@eslint/eslintrc@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "@eslint/eslintrc@npm:3.2.0"
+ dependencies:
+ ajv: "npm:^6.12.4"
+ debug: "npm:^4.3.2"
+ espree: "npm:^10.0.1"
+ globals: "npm:^14.0.0"
+ ignore: "npm:^5.2.0"
+ import-fresh: "npm:^3.2.1"
+ js-yaml: "npm:^4.1.0"
+ minimatch: "npm:^3.1.2"
+ strip-json-comments: "npm:^3.1.1"
+ checksum: 10c0/43867a07ff9884d895d9855edba41acf325ef7664a8df41d957135a81a477ff4df4196f5f74dc3382627e5cc8b7ad6b815c2cea1b58f04a75aced7c43414ab8b
+ languageName: node
+ linkType: hard
+
+"@eslint/js@npm:9.16.0, @eslint/js@npm:^9.16.0":
+ version: 9.16.0
+ resolution: "@eslint/js@npm:9.16.0"
+ checksum: 10c0/a55846a4ddade720662d36682f3eaaf38eac06eeee12c83bb837bba2b7d550dadcb3445b104219f0bc1da2e09b4fe5fb5ba123b8338c8c787bcfbd540878df75
+ languageName: node
+ linkType: hard
+
+"@eslint/object-schema@npm:^2.1.4":
+ version: 2.1.4
+ resolution: "@eslint/object-schema@npm:2.1.4"
+ checksum: 10c0/e9885532ea70e483fb007bf1275968b05bb15ebaa506d98560c41a41220d33d342e19023d5f2939fed6eb59676c1bda5c847c284b4b55fce521d282004da4dda
+ languageName: node
+ linkType: hard
+
+"@eslint/plugin-kit@npm:^0.2.3":
+ version: 0.2.3
+ resolution: "@eslint/plugin-kit@npm:0.2.3"
+ dependencies:
+ levn: "npm:^0.4.1"
+ checksum: 10c0/89a8035976bb1780e3fa8ffe682df013bd25f7d102d991cecd3b7c297f4ce8c1a1b6805e76dd16465b5353455b670b545eff2b4ec3133e0eab81a5f9e99bd90f
+ languageName: node
+ linkType: hard
+
+"@humanfs/core@npm:^0.19.1":
+ version: 0.19.1
+ resolution: "@humanfs/core@npm:0.19.1"
+ checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67
+ languageName: node
+ linkType: hard
+
+"@humanfs/node@npm:^0.16.6":
+ version: 0.16.6
+ resolution: "@humanfs/node@npm:0.16.6"
+ dependencies:
+ "@humanfs/core": "npm:^0.19.1"
+ "@humanwhocodes/retry": "npm:^0.3.0"
+ checksum: 10c0/8356359c9f60108ec204cbd249ecd0356667359b2524886b357617c4a7c3b6aace0fd5a369f63747b926a762a88f8a25bc066fa1778508d110195ce7686243e1
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/module-importer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@humanwhocodes/module-importer@npm:1.0.1"
+ checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/retry@npm:^0.3.0":
+ version: 0.3.1
+ resolution: "@humanwhocodes/retry@npm:0.3.1"
+ checksum: 10c0/f0da1282dfb45e8120480b9e2e275e2ac9bbe1cf016d046fdad8e27cc1285c45bb9e711681237944445157b430093412b4446c1ab3fc4bb037861b5904101d3b
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/retry@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "@humanwhocodes/retry@npm:0.4.1"
+ checksum: 10c0/be7bb6841c4c01d0b767d9bb1ec1c9359ee61421ce8ba66c249d035c5acdfd080f32d55a5c9e859cdd7868788b8935774f65b2caf24ec0b7bd7bf333791f063b
+ languageName: node
+ linkType: hard
+
+"@isaacs/cliui@npm:^8.0.2":
+ version: 8.0.2
+ resolution: "@isaacs/cliui@npm:8.0.2"
+ dependencies:
+ string-width: "npm:^5.1.2"
+ string-width-cjs: "npm:string-width@^4.2.0"
+ strip-ansi: "npm:^7.0.1"
+ strip-ansi-cjs: "npm:strip-ansi@^6.0.1"
+ wrap-ansi: "npm:^8.1.0"
+ wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0"
+ checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e
+ languageName: node
+ linkType: hard
+
+"@istanbuljs/schema@npm:^0.1.2":
+ version: 0.1.3
+ resolution: "@istanbuljs/schema@npm:0.1.3"
+ checksum: 10c0/61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a
+ languageName: node
+ linkType: hard
+
+"@jest/schemas@npm:^29.6.3":
+ version: 29.6.3
+ resolution: "@jest/schemas@npm:29.6.3"
+ dependencies:
+ "@sinclair/typebox": "npm:^0.27.8"
+ checksum: 10c0/b329e89cd5f20b9278ae1233df74016ebf7b385e0d14b9f4c1ad18d096c4c19d1e687aa113a9c976b16ec07f021ae53dea811fb8c1248a50ac34fbe009fdf6be
+ languageName: node
+ linkType: hard
+
+"@jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "@jridgewell/gen-mapping@npm:0.3.5"
+ dependencies:
+ "@jridgewell/set-array": "npm:^1.2.1"
+ "@jridgewell/sourcemap-codec": "npm:^1.4.10"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/1be4fd4a6b0f41337c4f5fdf4afc3bd19e39c3691924817108b82ffcb9c9e609c273f936932b9fba4b3a298ce2eb06d9bff4eb1cc3bd81c4f4ee1b4917e25feb
+ languageName: node
+ linkType: hard
+
+"@jridgewell/resolve-uri@npm:^3.1.0":
+ version: 3.1.2
+ resolution: "@jridgewell/resolve-uri@npm:3.1.2"
+ checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e
+ languageName: node
+ linkType: hard
+
+"@jridgewell/set-array@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "@jridgewell/set-array@npm:1.2.1"
+ checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4
+ languageName: node
+ linkType: hard
+
+"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0":
+ version: 1.5.0
+ resolution: "@jridgewell/sourcemap-codec@npm:1.5.0"
+ checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18
+ languageName: node
+ linkType: hard
+
+"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24":
+ version: 0.3.25
+ resolution: "@jridgewell/trace-mapping@npm:0.3.25"
+ dependencies:
+ "@jridgewell/resolve-uri": "npm:^3.1.0"
+ "@jridgewell/sourcemap-codec": "npm:^1.4.14"
+ checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4
+ languageName: node
+ linkType: hard
+
+"@jsdevtools/ez-spawn@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "@jsdevtools/ez-spawn@npm:3.0.4"
+ dependencies:
+ call-me-maybe: "npm:^1.0.1"
+ cross-spawn: "npm:^7.0.3"
+ string-argv: "npm:^0.3.1"
+ type-detect: "npm:^4.0.8"
+ checksum: 10c0/fb56f99c4d09ccaeace4ebaecfa31ab1ff90517d5ca51dbd624f4b9ab489eee469504ab33a12a2bc8b5f0a35ee61e139cc087b242ad7947c61674454cb41c75e
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.scandir@npm:2.1.5":
+ version: 2.1.5
+ resolution: "@nodelib/fs.scandir@npm:2.1.5"
+ dependencies:
+ "@nodelib/fs.stat": "npm:2.0.5"
+ run-parallel: "npm:^1.1.9"
+ checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2":
+ version: 2.0.5
+ resolution: "@nodelib/fs.stat@npm:2.0.5"
+ checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.walk@npm:^1.2.3":
+ version: 1.2.8
+ resolution: "@nodelib/fs.walk@npm:1.2.8"
+ dependencies:
+ "@nodelib/fs.scandir": "npm:2.1.5"
+ fastq: "npm:^1.6.0"
+ checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1
+ languageName: node
+ linkType: hard
+
+"@nolyfill/is-core-module@npm:1.0.39":
+ version: 1.0.39
+ resolution: "@nolyfill/is-core-module@npm:1.0.39"
+ checksum: 10c0/34ab85fdc2e0250879518841f74a30c276bca4f6c3e13526d2d1fe515e1adf6d46c25fcd5989d22ea056d76f7c39210945180b4859fc83b050e2da411aa86289
+ languageName: node
+ linkType: hard
+
+"@npmcli/agent@npm:^2.0.0":
+ version: 2.2.2
+ resolution: "@npmcli/agent@npm:2.2.2"
+ dependencies:
+ agent-base: "npm:^7.1.0"
+ http-proxy-agent: "npm:^7.0.0"
+ https-proxy-agent: "npm:^7.0.1"
+ lru-cache: "npm:^10.0.1"
+ socks-proxy-agent: "npm:^8.0.3"
+ checksum: 10c0/325e0db7b287d4154ecd164c0815c08007abfb07653cc57bceded17bb7fd240998a3cbdbe87d700e30bef494885eccc725ab73b668020811d56623d145b524ae
+ languageName: node
+ linkType: hard
+
+"@npmcli/fs@npm:^3.1.0":
+ version: 3.1.1
+ resolution: "@npmcli/fs@npm:3.1.1"
+ dependencies:
+ semver: "npm:^7.3.5"
+ checksum: 10c0/c37a5b4842bfdece3d14dfdb054f73fe15ed2d3da61b34ff76629fb5b1731647c49166fd2a8bf8b56fcfa51200382385ea8909a3cbecdad612310c114d3f6c99
+ languageName: node
+ linkType: hard
+
+"@pkgjs/parseargs@npm:^0.11.0":
+ version: 0.11.0
+ resolution: "@pkgjs/parseargs@npm:0.11.0"
+ checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm-eabi@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-android-arm-eabi@npm:4.28.0"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm64@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-android-arm64@npm:4.28.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-arm64@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-darwin-arm64@npm:4.28.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-x64@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-darwin-x64@npm:4.28.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-arm64@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-freebsd-arm64@npm:4.28.0"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-x64@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-freebsd-x64@npm:4.28.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.28.0"
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-musleabihf@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.28.0"
+ conditions: os=linux & cpu=arm & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-gnu@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.28.0"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-musl@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-arm64-musl@npm:4.28.0"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-powerpc64le-gnu@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.28.0"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-riscv64-gnu@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.28.0"
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-s390x-gnu@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.28.0"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-gnu@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-x64-gnu@npm:4.28.0"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-musl@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-linux-x64-musl@npm:4.28.0"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-arm64-msvc@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.28.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-ia32-msvc@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.28.0"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-x64-msvc@npm:4.28.0":
+ version: 4.28.0
+ resolution: "@rollup/rollup-win32-x64-msvc@npm:4.28.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@sinclair/typebox@npm:^0.27.8":
+ version: 0.27.8
+ resolution: "@sinclair/typebox@npm:0.27.8"
+ checksum: 10c0/ef6351ae073c45c2ac89494dbb3e1f87cc60a93ce4cde797b782812b6f97da0d620ae81973f104b43c9b7eaa789ad20ba4f6a1359f1cc62f63729a55a7d22d4e
+ languageName: node
+ linkType: hard
+
+"@sindresorhus/merge-streams@npm:^2.1.0":
+ version: 2.3.0
+ resolution: "@sindresorhus/merge-streams@npm:2.3.0"
+ checksum: 10c0/69ee906f3125fb2c6bb6ec5cdd84e8827d93b49b3892bce8b62267116cc7e197b5cccf20c160a1d32c26014ecd14470a72a5e3ee37a58f1d6dadc0db1ccf3894
+ languageName: node
+ linkType: hard
+
+"@stylistic/eslint-plugin@npm:^2.11.0":
+ version: 2.11.0
+ resolution: "@stylistic/eslint-plugin@npm:2.11.0"
+ dependencies:
+ "@typescript-eslint/utils": "npm:^8.13.0"
+ eslint-visitor-keys: "npm:^4.2.0"
+ espree: "npm:^10.3.0"
+ estraverse: "npm:^5.3.0"
+ picomatch: "npm:^4.0.2"
+ peerDependencies:
+ eslint: ">=8.40.0"
+ checksum: 10c0/6ca19b6656be5ed657cf4d1920602fb27144dc5d51ba188e0bdcb2a4e0b740d4fdb27052fc268d164fa1269c972aeab15541c9e15b3ff4b7884ecae47f18ff67
+ languageName: node
+ linkType: hard
+
+"@types/common-tags@npm:^1.8.4":
+ version: 1.8.4
+ resolution: "@types/common-tags@npm:1.8.4"
+ checksum: 10c0/899c887785812e1805e9bdd6f1110811b01384888f9a8e539174b49484e40f29f99cd66659c0c4865339338eee59b16821b9b728b98efc7c1118767192f199d2
+ languageName: node
+ linkType: hard
+
+"@types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
+ version: 1.0.6
+ resolution: "@types/estree@npm:1.0.6"
+ checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a
+ languageName: node
+ linkType: hard
+
+"@types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9":
+ version: 7.0.15
+ resolution: "@types/json-schema@npm:7.0.15"
+ checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:~18.18.0":
+ version: 18.18.14
+ resolution: "@types/node@npm:18.18.14"
+ dependencies:
+ undici-types: "npm:~5.26.4"
+ checksum: 10c0/7ab33be7e9ed0501bbbf1e62006b441a1ec5a8969b4f4df796919f3fc851604e2119947b72696e4049dd638a10b27e6f6b4cfaa469787d548d4d9c09fb945968
+ languageName: node
+ linkType: hard
+
+"@types/semver@npm:^7.3.12":
+ version: 7.5.8
+ resolution: "@types/semver@npm:7.5.8"
+ checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/eslint-plugin@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/eslint-plugin@npm:8.17.0"
+ dependencies:
+ "@eslint-community/regexpp": "npm:^4.10.0"
+ "@typescript-eslint/scope-manager": "npm:8.17.0"
+ "@typescript-eslint/type-utils": "npm:8.17.0"
+ "@typescript-eslint/utils": "npm:8.17.0"
+ "@typescript-eslint/visitor-keys": "npm:8.17.0"
+ graphemer: "npm:^1.4.0"
+ ignore: "npm:^5.3.1"
+ natural-compare: "npm:^1.4.0"
+ ts-api-utils: "npm:^1.3.0"
+ peerDependencies:
+ "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0
+ eslint: ^8.57.0 || ^9.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/d78778173571a9a1370345bc2aa3e850235a489d16b8a8b5ba3086b988bbef7549bdae38e509d7a679ba3179c688cc5a408376b158be402770836e94ffc9602d
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/parser@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/parser@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/scope-manager": "npm:8.17.0"
+ "@typescript-eslint/types": "npm:8.17.0"
+ "@typescript-eslint/typescript-estree": "npm:8.17.0"
+ "@typescript-eslint/visitor-keys": "npm:8.17.0"
+ debug: "npm:^4.3.4"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/2543deadf01302a92d3b6f58a4c14f98d8936c4d976e7da05e3bb65608f19d8de93b25282e343c304eca3e3f37f2ac23e97fa9c11c6edff36dd2d4f6b601a630
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/rule-tester@npm:^8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/rule-tester@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/typescript-estree": "npm:8.17.0"
+ "@typescript-eslint/utils": "npm:8.17.0"
+ ajv: "npm:^6.12.6"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ lodash.merge: "npm:4.6.2"
+ semver: "npm:^7.6.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ checksum: 10c0/27541e1f82cb58049279883e70414a606d96c0f2fff12782408c119456ce0e1f335978da188f6f62df294bc712dc0805bc7e9e1b7eb130271b328819e331f3c2
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/scope-manager@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ checksum: 10c0/861253235576c1c5c1772d23cdce1418c2da2618a479a7de4f6114a12a7ca853011a1e530525d0931c355a8fd237b9cd828fac560f85f9623e24054fd024726f
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/scope-manager@npm:8.17.0, @typescript-eslint/scope-manager@npm:^8.1.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/scope-manager@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.17.0"
+ "@typescript-eslint/visitor-keys": "npm:8.17.0"
+ checksum: 10c0/0c08d14240bad4b3f6874f08ba80b29db1a6657437089a6f109db458c544d835bcdc06ba9140bb4f835233ba4326d9a86e6cf6bdb5209960d2f7025aa3191f4f
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/type-utils@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/type-utils@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/typescript-estree": "npm:8.17.0"
+ "@typescript-eslint/utils": "npm:8.17.0"
+ debug: "npm:^4.3.4"
+ ts-api-utils: "npm:^1.3.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/6138ec71b5692d4b5e0bf3d7f66a6fa4e91ddea7031907b0ac45a7693df0a2f4cc5bca7218311e0639620d636ceb7efec83a137dfcd5938304d873b774fcc8bd
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/types@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/types@npm:5.62.0"
+ checksum: 10c0/7febd3a7f0701c0b927e094f02e82d8ee2cada2b186fcb938bc2b94ff6fbad88237afc304cbaf33e82797078bbbb1baf91475f6400912f8b64c89be79bfa4ddf
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/types@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/types@npm:8.17.0"
+ checksum: 10c0/26b1bf9dfc3ee783c85c6f354b84c28706d5689d777f3ff2de2cb496e45f9d0189c0d561c03ccbc8b24712438be17cf63dd0871ff3ca2083e7f48749770d1893
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/typescript-estree@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ debug: "npm:^4.3.4"
+ globby: "npm:^11.1.0"
+ is-glob: "npm:^4.0.3"
+ semver: "npm:^7.3.7"
+ tsutils: "npm:^3.21.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/d7984a3e9d56897b2481940ec803cb8e7ead03df8d9cfd9797350be82ff765dfcf3cfec04e7355e1779e948da8f02bc5e11719d07a596eb1cb995c48a95e38cf
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/typescript-estree@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/typescript-estree@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.17.0"
+ "@typescript-eslint/visitor-keys": "npm:8.17.0"
+ debug: "npm:^4.3.4"
+ fast-glob: "npm:^3.3.2"
+ is-glob: "npm:^4.0.3"
+ minimatch: "npm:^9.0.4"
+ semver: "npm:^7.6.0"
+ ts-api-utils: "npm:^1.3.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/523013f9b5cf2c58c566868e4c3b0b9ac1b4807223a6d64e2a7c58e01e53b6587ba61f1a8241eade361f3f426d6057657515473176141ef8aebb352bc0d223ce
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/utils@npm:8.17.0, @typescript-eslint/utils@npm:^8.1.0, @typescript-eslint/utils@npm:^8.13.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/utils@npm:8.17.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.4.0"
+ "@typescript-eslint/scope-manager": "npm:8.17.0"
+ "@typescript-eslint/types": "npm:8.17.0"
+ "@typescript-eslint/typescript-estree": "npm:8.17.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/a9785ae5f7e7b51d521dc3f48b15093948e4fcd03352c0b60f39bae366cbc935947d215f91e2ae3182d52fa6affb5ccbb50feff487bd1209011f3e0da02cdf07
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/utils@npm:^5.38.1":
+ version: 5.62.0
+ resolution: "@typescript-eslint/utils@npm:5.62.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@types/json-schema": "npm:^7.0.9"
+ "@types/semver": "npm:^7.3.12"
+ "@typescript-eslint/scope-manager": "npm:5.62.0"
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/typescript-estree": "npm:5.62.0"
+ eslint-scope: "npm:^5.1.1"
+ semver: "npm:^7.3.7"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10c0/f09b7d9952e4a205eb1ced31d7684dd55cee40bf8c2d78e923aa8a255318d97279825733902742c09d8690f37a50243f4c4d383ab16bd7aefaf9c4b438f785e1
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/visitor-keys@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ eslint-visitor-keys: "npm:^3.3.0"
+ checksum: 10c0/7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/visitor-keys@npm:8.17.0":
+ version: 8.17.0
+ resolution: "@typescript-eslint/visitor-keys@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.17.0"
+ eslint-visitor-keys: "npm:^4.2.0"
+ checksum: 10c0/9144c4e4a63034fb2031a0ee1fc77e80594f30cab3faafa9a1f7f83782695774dd32fac8986f260698b4e150b4dd52444f2611c07e4c101501f08353eb47c82c
+ languageName: node
+ linkType: hard
+
+"@typescript/vfs@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "@typescript/vfs@npm:1.6.0"
+ dependencies:
+ debug: "npm:^4.1.1"
+ peerDependencies:
+ typescript: "*"
+ checksum: 10c0/35e17d92f0d4f33c4be12fc4468196788794bc2edc1a371f1023c42314f6d1e0e851f07b45732a634ef750e61e2ef8769e8ab4f6a6c511cea8da397fa87852ff
+ languageName: node
+ linkType: hard
+
+"@vitest/coverage-v8@npm:^2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/coverage-v8@npm:2.1.8"
+ dependencies:
+ "@ampproject/remapping": "npm:^2.3.0"
+ "@bcoe/v8-coverage": "npm:^0.2.3"
+ debug: "npm:^4.3.7"
+ istanbul-lib-coverage: "npm:^3.2.2"
+ istanbul-lib-report: "npm:^3.0.1"
+ istanbul-lib-source-maps: "npm:^5.0.6"
+ istanbul-reports: "npm:^3.1.7"
+ magic-string: "npm:^0.30.12"
+ magicast: "npm:^0.3.5"
+ std-env: "npm:^3.8.0"
+ test-exclude: "npm:^7.0.1"
+ tinyrainbow: "npm:^1.2.0"
+ peerDependencies:
+ "@vitest/browser": 2.1.8
+ vitest: 2.1.8
+ peerDependenciesMeta:
+ "@vitest/browser":
+ optional: true
+ checksum: 10c0/b228a23bbaf0eae07ac939399f968b0def2df786091948a12d614919db3f5b6e46db7a1ab4f9d05d5d7f696afd53133a67abc25915f85480cd032442664ac725
+ languageName: node
+ linkType: hard
+
+"@vitest/eslint-plugin@npm:^1.1.14":
+ version: 1.1.14
+ resolution: "@vitest/eslint-plugin@npm:1.1.14"
+ peerDependencies:
+ "@typescript-eslint/utils": ">= 8.0"
+ eslint: ">= 8.57.0"
+ typescript: ">= 5.0.0"
+ vitest: "*"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ vitest:
+ optional: true
+ checksum: 10c0/83fe9dfa2b5d22f576cbd89c7f039c79f81c172552972aa4688d098dac712a0d35e10f54e9626928598da8615f768a88d637aa873c2bb8fe409684b8349dae67
+ languageName: node
+ linkType: hard
+
+"@vitest/expect@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/expect@npm:2.1.8"
+ dependencies:
+ "@vitest/spy": "npm:2.1.8"
+ "@vitest/utils": "npm:2.1.8"
+ chai: "npm:^5.1.2"
+ tinyrainbow: "npm:^1.2.0"
+ checksum: 10c0/6fbf4abc2360efe4d3671d3425f8bb6012fe2dd932a88720d8b793030b766ba260494822c721d3fc497afe52373515c7e150635a95c25f6e1b567f86155c5408
+ languageName: node
+ linkType: hard
+
+"@vitest/mocker@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/mocker@npm:2.1.8"
+ dependencies:
+ "@vitest/spy": "npm:2.1.8"
+ estree-walker: "npm:^3.0.3"
+ magic-string: "npm:^0.30.12"
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+ checksum: 10c0/b4113ed8a57c0f60101d02e1b1769357a346ecd55ded499eab384d52106fd4b12d51e9aaa6db98f47de0d56662477be0ed8d46d6dfa84c235f9e1b234709814e
+ languageName: node
+ linkType: hard
+
+"@vitest/pretty-format@npm:2.1.8, @vitest/pretty-format@npm:^2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/pretty-format@npm:2.1.8"
+ dependencies:
+ tinyrainbow: "npm:^1.2.0"
+ checksum: 10c0/1dc5c9b1c7c7e78e46a2a16033b6b20be05958bbebc5a5b78f29e32718c80252034804fccd23f34db6b3583239db47e68fc5a8e41942c54b8047cc3b4133a052
+ languageName: node
+ linkType: hard
+
+"@vitest/runner@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/runner@npm:2.1.8"
+ dependencies:
+ "@vitest/utils": "npm:2.1.8"
+ pathe: "npm:^1.1.2"
+ checksum: 10c0/d0826a71494adeafc8c6478257f584d11655145c83e2d8f94c17301d7059c7463ad768a69379e394c50838a7435abcc9255a6b7d8894f5ee06b153e314683a75
+ languageName: node
+ linkType: hard
+
+"@vitest/snapshot@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/snapshot@npm:2.1.8"
+ dependencies:
+ "@vitest/pretty-format": "npm:2.1.8"
+ magic-string: "npm:^0.30.12"
+ pathe: "npm:^1.1.2"
+ checksum: 10c0/8d7a77a52e128630ea737ee0a0fe746d1d325cac5848326861dbf042844da4d5c1a5145539ae0ed1a3f0b0363506e98d86f2679fadf114ec4b987f1eb616867b
+ languageName: node
+ linkType: hard
+
+"@vitest/spy@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/spy@npm:2.1.8"
+ dependencies:
+ tinyspy: "npm:^3.0.2"
+ checksum: 10c0/9740f10772ede004ea7f9ffb8a6c3011341d75d9d7f2d4d181b123a701c4691e942f38cf1700684a3bb5eea3c78addf753fd8cdf78c51d8eadc3bada6fadf8f2
+ languageName: node
+ linkType: hard
+
+"@vitest/utils@npm:2.1.8":
+ version: 2.1.8
+ resolution: "@vitest/utils@npm:2.1.8"
+ dependencies:
+ "@vitest/pretty-format": "npm:2.1.8"
+ loupe: "npm:^3.1.2"
+ tinyrainbow: "npm:^1.2.0"
+ checksum: 10c0/d4a29ecd8f6c24c790e4c009f313a044d89e664e331bc9c3cfb57fe1380fb1d2999706dbbfc291f067d6c489602e76d00435309fbc906197c0d01f831ca17d64
+ languageName: node
+ linkType: hard
+
+"abbrev@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "abbrev@npm:2.0.0"
+ checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372
+ languageName: node
+ linkType: hard
+
+"acorn-jsx@npm:^5.3.2":
+ version: 5.3.2
+ resolution: "acorn-jsx@npm:5.3.2"
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1
+ languageName: node
+ linkType: hard
+
+"acorn@npm:^8.12.1, acorn@npm:^8.14.0":
+ version: 8.14.0
+ resolution: "acorn@npm:8.14.0"
+ bin:
+ acorn: bin/acorn
+ checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7
+ languageName: node
+ linkType: hard
+
+"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "agent-base@npm:7.1.1"
+ dependencies:
+ debug: "npm:^4.3.4"
+ checksum: 10c0/e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50
+ languageName: node
+ linkType: hard
+
+"aggregate-error@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "aggregate-error@npm:3.1.0"
+ dependencies:
+ clean-stack: "npm:^2.0.0"
+ indent-string: "npm:^4.0.0"
+ checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039
+ languageName: node
+ linkType: hard
+
+"ajv@npm:^6.12.4, ajv@npm:^6.12.6":
+ version: 6.12.6
+ resolution: "ajv@npm:6.12.6"
+ dependencies:
+ fast-deep-equal: "npm:^3.1.1"
+ fast-json-stable-stringify: "npm:^2.0.0"
+ json-schema-traverse: "npm:^0.4.1"
+ uri-js: "npm:^4.2.2"
+ checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71
+ languageName: node
+ linkType: hard
+
+"ajv@npm:^8.11.2":
+ version: 8.17.1
+ resolution: "ajv@npm:8.17.1"
+ dependencies:
+ fast-deep-equal: "npm:^3.1.3"
+ fast-uri: "npm:^3.0.1"
+ json-schema-traverse: "npm:^1.0.0"
+ require-from-string: "npm:^2.0.2"
+ checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35
+ languageName: node
+ linkType: hard
+
+"ansi-regex@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "ansi-regex@npm:5.0.1"
+ checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737
+ languageName: node
+ linkType: hard
+
+"ansi-regex@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "ansi-regex@npm:6.0.1"
+ checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0":
+ version: 4.3.0
+ resolution: "ansi-styles@npm:4.3.0"
+ dependencies:
+ color-convert: "npm:^2.0.1"
+ checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^5.0.0":
+ version: 5.2.0
+ resolution: "ansi-styles@npm:5.2.0"
+ checksum: 10c0/9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^6.1.0":
+ version: 6.2.1
+ resolution: "ansi-styles@npm:6.2.1"
+ checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c
+ languageName: node
+ linkType: hard
+
+"any-promise@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "any-promise@npm:1.3.0"
+ checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889
+ languageName: node
+ linkType: hard
+
+"anymatch@npm:~3.1.2":
+ version: 3.1.3
+ resolution: "anymatch@npm:3.1.3"
+ dependencies:
+ normalize-path: "npm:^3.0.0"
+ picomatch: "npm:^2.0.4"
+ checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac
+ languageName: node
+ linkType: hard
+
+"argparse@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "argparse@npm:2.0.1"
+ checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e
+ languageName: node
+ linkType: hard
+
+"array-union@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "array-union@npm:2.1.0"
+ checksum: 10c0/429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962
+ languageName: node
+ linkType: hard
+
+"assertion-error@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "assertion-error@npm:2.0.1"
+ checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8
+ languageName: node
+ linkType: hard
+
+"balanced-match@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "balanced-match@npm:1.0.2"
+ checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee
+ languageName: node
+ linkType: hard
+
+"binary-extensions@npm:^2.0.0":
+ version: 2.3.0
+ resolution: "binary-extensions@npm:2.3.0"
+ checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5
+ languageName: node
+ linkType: hard
+
+"boolean@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "boolean@npm:3.2.0"
+ checksum: 10c0/6a0dc9668f6f3dda42a53c181fcbdad223169c8d87b6c4011b87a8b14a21770efb2934a778f063d7ece17280f8c06d313c87f7b834bb1dd526a867ffcd00febf
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^1.1.7":
+ version: 1.1.11
+ resolution: "brace-expansion@npm:1.1.11"
+ dependencies:
+ balanced-match: "npm:^1.0.0"
+ concat-map: "npm:0.0.1"
+ checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "brace-expansion@npm:2.0.1"
+ dependencies:
+ balanced-match: "npm:^1.0.0"
+ checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f
+ languageName: node
+ linkType: hard
+
+"braces@npm:^3.0.3, braces@npm:~3.0.2":
+ version: 3.0.3
+ resolution: "braces@npm:3.0.3"
+ dependencies:
+ fill-range: "npm:^7.1.1"
+ checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04
+ languageName: node
+ linkType: hard
+
+"bumpp@npm:^9.8.1":
+ version: 9.8.1
+ resolution: "bumpp@npm:9.8.1"
+ dependencies:
+ "@jsdevtools/ez-spawn": "npm:^3.0.4"
+ c12: "npm:^1.11.2"
+ cac: "npm:^6.7.14"
+ escalade: "npm:^3.2.0"
+ js-yaml: "npm:^4.1.0"
+ jsonc-parser: "npm:^3.3.1"
+ prompts: "npm:^2.4.2"
+ semver: "npm:^7.6.3"
+ tinyglobby: "npm:^0.2.10"
+ bin:
+ bumpp: bin/bumpp.js
+ checksum: 10c0/f7952d92f50ac84ff9473696862e6dda6e500e0721e728bdc47c36c059e115a55d116fbe4fbab691210d65b6b5684784ccbb9e2f00c5614c43136617571ec491
+ languageName: node
+ linkType: hard
+
+"bundle-require@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "bundle-require@npm:5.0.0"
+ dependencies:
+ load-tsconfig: "npm:^0.2.3"
+ peerDependencies:
+ esbuild: ">=0.18"
+ checksum: 10c0/92c46df02586e0ebd66ee4831c9b5775adb3c32a43fe2b2aaf7bc675135c141f751de6a9a26b146d64c607c5b40f9eef5f10dce3c364f602d4bed268444c32c6
+ languageName: node
+ linkType: hard
+
+"c12@npm:^1.11.2":
+ version: 1.11.2
+ resolution: "c12@npm:1.11.2"
+ dependencies:
+ chokidar: "npm:^3.6.0"
+ confbox: "npm:^0.1.7"
+ defu: "npm:^6.1.4"
+ dotenv: "npm:^16.4.5"
+ giget: "npm:^1.2.3"
+ jiti: "npm:^1.21.6"
+ mlly: "npm:^1.7.1"
+ ohash: "npm:^1.1.3"
+ pathe: "npm:^1.1.2"
+ perfect-debounce: "npm:^1.0.0"
+ pkg-types: "npm:^1.2.0"
+ rc9: "npm:^2.1.2"
+ peerDependencies:
+ magicast: ^0.3.4
+ peerDependenciesMeta:
+ magicast:
+ optional: true
+ checksum: 10c0/6c805e563b92109d7c4b7f7526b0fcf91c71ff50a30c316c3f77ccd3a8da8135db343ca9d8720b3ce0472ff1ee451edb8decef6e136a3b3af1ec2ec72b647a60
+ languageName: node
+ linkType: hard
+
+"cac@npm:^6.7.14":
+ version: 6.7.14
+ resolution: "cac@npm:6.7.14"
+ checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10
+ languageName: node
+ linkType: hard
+
+"cacache@npm:^18.0.0":
+ version: 18.0.4
+ resolution: "cacache@npm:18.0.4"
+ dependencies:
+ "@npmcli/fs": "npm:^3.1.0"
+ fs-minipass: "npm:^3.0.0"
+ glob: "npm:^10.2.2"
+ lru-cache: "npm:^10.0.1"
+ minipass: "npm:^7.0.3"
+ minipass-collect: "npm:^2.0.1"
+ minipass-flush: "npm:^1.0.5"
+ minipass-pipeline: "npm:^1.2.4"
+ p-map: "npm:^4.0.0"
+ ssri: "npm:^10.0.0"
+ tar: "npm:^6.1.11"
+ unique-filename: "npm:^3.0.0"
+ checksum: 10c0/6c055bafed9de4f3dcc64ac3dc7dd24e863210902b7c470eb9ce55a806309b3efff78033e3d8b4f7dcc5d467f2db43c6a2857aaaf26f0094b8a351d44c42179f
+ languageName: node
+ linkType: hard
+
+"call-me-maybe@npm:^1.0.1":
+ version: 1.0.2
+ resolution: "call-me-maybe@npm:1.0.2"
+ checksum: 10c0/8eff5dbb61141ebb236ed71b4e9549e488bcb5451c48c11e5667d5c75b0532303788a1101e6978cafa2d0c8c1a727805599c2741e3e0982855c9f1d78cd06c9f
+ languageName: node
+ linkType: hard
+
+"callsites@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "callsites@npm:3.1.0"
+ checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301
+ languageName: node
+ linkType: hard
+
+"chai@npm:^5.1.2":
+ version: 5.1.2
+ resolution: "chai@npm:5.1.2"
+ dependencies:
+ assertion-error: "npm:^2.0.1"
+ check-error: "npm:^2.1.1"
+ deep-eql: "npm:^5.0.1"
+ loupe: "npm:^3.1.0"
+ pathval: "npm:^2.0.0"
+ checksum: 10c0/6c04ff8495b6e535df9c1b062b6b094828454e9a3c9493393e55b2f4dbff7aa2a29a4645133cad160fb00a16196c4dc03dc9bb37e1f4ba9df3b5f50d7533a736
+ languageName: node
+ linkType: hard
+
+"chalk@npm:^4.0.0":
+ version: 4.1.2
+ resolution: "chalk@npm:4.1.2"
+ dependencies:
+ ansi-styles: "npm:^4.1.0"
+ supports-color: "npm:^7.1.0"
+ checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880
+ languageName: node
+ linkType: hard
+
+"check-error@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "check-error@npm:2.1.1"
+ checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e
+ languageName: node
+ linkType: hard
+
+"chokidar@npm:^3.6.0":
+ version: 3.6.0
+ resolution: "chokidar@npm:3.6.0"
+ dependencies:
+ anymatch: "npm:~3.1.2"
+ braces: "npm:~3.0.2"
+ fsevents: "npm:~2.3.2"
+ glob-parent: "npm:~5.1.2"
+ is-binary-path: "npm:~2.1.0"
+ is-glob: "npm:~4.0.1"
+ normalize-path: "npm:~3.0.0"
+ readdirp: "npm:~3.6.0"
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462
+ languageName: node
+ linkType: hard
+
+"chokidar@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "chokidar@npm:4.0.1"
+ dependencies:
+ readdirp: "npm:^4.0.1"
+ checksum: 10c0/4bb7a3adc304059810bb6c420c43261a15bb44f610d77c35547addc84faa0374265c3adc67f25d06f363d9a4571962b02679268c40de07676d260de1986efea9
+ languageName: node
+ linkType: hard
+
+"chownr@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "chownr@npm:2.0.0"
+ checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6
+ languageName: node
+ linkType: hard
+
+"citty@npm:^0.1.6":
+ version: 0.1.6
+ resolution: "citty@npm:0.1.6"
+ dependencies:
+ consola: "npm:^3.2.3"
+ checksum: 10c0/d26ad82a9a4a8858c7e149d90b878a3eceecd4cfd3e2ed3cd5f9a06212e451fb4f8cbe0fa39a3acb1b3e8f18e22db8ee5def5829384bad50e823d4b301609b48
+ languageName: node
+ linkType: hard
+
+"clean-stack@npm:^2.0.0":
+ version: 2.2.0
+ resolution: "clean-stack@npm:2.2.0"
+ checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1
+ languageName: node
+ linkType: hard
+
+"color-convert@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "color-convert@npm:2.0.1"
+ dependencies:
+ color-name: "npm:~1.1.4"
+ checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7
+ languageName: node
+ linkType: hard
+
+"color-name@npm:~1.1.4":
+ version: 1.1.4
+ resolution: "color-name@npm:1.1.4"
+ checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
+ languageName: node
+ linkType: hard
+
+"commander@npm:^10.0.0":
+ version: 10.0.1
+ resolution: "commander@npm:10.0.1"
+ checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3
+ languageName: node
+ linkType: hard
+
+"commander@npm:^4.0.0":
+ version: 4.1.1
+ resolution: "commander@npm:4.1.1"
+ checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab
+ languageName: node
+ linkType: hard
+
+"common-tags@npm:^1.8.0":
+ version: 1.8.2
+ resolution: "common-tags@npm:1.8.2"
+ checksum: 10c0/23efe47ff0a1a7c91489271b3a1e1d2a171c12ec7f9b35b29b2fce51270124aff0ec890087e2bc2182c1cb746e232ab7561aaafe05f1e7452aea733d2bfe3f63
+ languageName: node
+ linkType: hard
+
+"concat-map@npm:0.0.1":
+ version: 0.0.1
+ resolution: "concat-map@npm:0.0.1"
+ checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f
+ languageName: node
+ linkType: hard
+
+"confbox@npm:^0.1.7, confbox@npm:^0.1.8":
+ version: 0.1.8
+ resolution: "confbox@npm:0.1.8"
+ checksum: 10c0/fc2c68d97cb54d885b10b63e45bd8da83a8a71459d3ecf1825143dd4c7f9f1b696b3283e07d9d12a144c1301c2ebc7842380bdf0014e55acc4ae1c9550102418
+ languageName: node
+ linkType: hard
+
+"consola@npm:^3.2.3":
+ version: 3.2.3
+ resolution: "consola@npm:3.2.3"
+ checksum: 10c0/c606220524ec88a05bb1baf557e9e0e04a0c08a9c35d7a08652d99de195c4ddcb6572040a7df57a18ff38bbc13ce9880ad032d56630cef27bef72768ef0ac078
+ languageName: node
+ linkType: hard
+
+"cosmiconfig@npm:^8.0.0":
+ version: 8.3.6
+ resolution: "cosmiconfig@npm:8.3.6"
+ dependencies:
+ import-fresh: "npm:^3.3.0"
+ js-yaml: "npm:^4.1.0"
+ parse-json: "npm:^5.2.0"
+ path-type: "npm:^4.0.0"
+ peerDependencies:
+ typescript: ">=4.9.5"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a
+ languageName: node
+ linkType: hard
+
+"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5":
+ version: 7.0.6
+ resolution: "cross-spawn@npm:7.0.6"
+ dependencies:
+ path-key: "npm:^3.1.0"
+ shebang-command: "npm:^2.0.0"
+ which: "npm:^2.0.1"
+ checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1
+ languageName: node
+ linkType: hard
+
+"debug@npm:4, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.7":
+ version: 4.3.7
+ resolution: "debug@npm:4.3.7"
+ dependencies:
+ ms: "npm:^2.1.3"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 10c0/1471db19c3b06d485a622d62f65947a19a23fbd0dd73f7fd3eafb697eec5360cde447fb075919987899b1a2096e85d35d4eb5a4de09a57600ac9cf7e6c8e768b
+ languageName: node
+ linkType: hard
+
+"debug@npm:^3.2.7":
+ version: 3.2.7
+ resolution: "debug@npm:3.2.7"
+ dependencies:
+ ms: "npm:^2.1.1"
+ checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a
+ languageName: node
+ linkType: hard
+
+"decamelize@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "decamelize@npm:5.0.1"
+ checksum: 10c0/3da71022bc1e85487810fa0833138effb599fa331ca21e179650e93a765d0c4dabeb1ecdd6ad1474fa0bacd2457953c63ea335afb6e53b35f2b4bf779514e2a3
+ languageName: node
+ linkType: hard
+
+"deep-eql@npm:^5.0.1":
+ version: 5.0.2
+ resolution: "deep-eql@npm:5.0.2"
+ checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247
+ languageName: node
+ linkType: hard
+
+"deep-is@npm:^0.1.3":
+ version: 0.1.4
+ resolution: "deep-is@npm:0.1.4"
+ checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c
+ languageName: node
+ linkType: hard
+
+"deepmerge@npm:^4.2.2":
+ version: 4.3.1
+ resolution: "deepmerge@npm:4.3.1"
+ checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044
+ languageName: node
+ linkType: hard
+
+"defu@npm:^6.1.4":
+ version: 6.1.4
+ resolution: "defu@npm:6.1.4"
+ checksum: 10c0/2d6cc366262dc0cb8096e429368e44052fdf43ed48e53ad84cc7c9407f890301aa5fcb80d0995abaaf842b3949f154d060be4160f7a46cb2bc2f7726c81526f5
+ languageName: node
+ linkType: hard
+
+"destr@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "destr@npm:2.0.3"
+ checksum: 10c0/10e7eff5149e2839a4dd29a1e9617c3c675a3b53608d78d74fc6f4abc31daa977e6de08e0eea78965527a0d5a35467ae2f9624e0a4646d54aa1162caa094473e
+ languageName: node
+ linkType: hard
+
+"diff-sequences@npm:^29.6.3":
+ version: 29.6.3
+ resolution: "diff-sequences@npm:29.6.3"
+ checksum: 10c0/32e27ac7dbffdf2fb0eb5a84efd98a9ad084fbabd5ac9abb8757c6770d5320d2acd172830b28c4add29bb873d59420601dfc805ac4064330ce59b1adfd0593b2
+ languageName: node
+ linkType: hard
+
+"dir-glob@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "dir-glob@npm:3.0.1"
+ dependencies:
+ path-type: "npm:^4.0.0"
+ checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c
+ languageName: node
+ linkType: hard
+
+"doctrine@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "doctrine@npm:3.0.0"
+ dependencies:
+ esutils: "npm:^2.0.2"
+ checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520
+ languageName: node
+ linkType: hard
+
+"dot-prop@npm:^7.2.0":
+ version: 7.2.0
+ resolution: "dot-prop@npm:7.2.0"
+ dependencies:
+ type-fest: "npm:^2.11.2"
+ checksum: 10c0/2621702a01e7a47730e3a8e2938a406afc79b62fbb77bd1394e786ff13776673904bf0a4fc6b812eb9849ec71034e9fc1019a9e0bbe91f84010d8a8088cd41a9
+ languageName: node
+ linkType: hard
+
+"dotenv@npm:^16.4.5":
+ version: 16.4.5
+ resolution: "dotenv@npm:16.4.5"
+ checksum: 10c0/48d92870076832af0418b13acd6e5a5a3e83bb00df690d9812e94b24aff62b88ade955ac99a05501305b8dc8f1b0ee7638b18493deb6fe93d680e5220936292f
+ languageName: node
+ linkType: hard
+
+"eastasianwidth@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "eastasianwidth@npm:0.2.0"
+ checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39
+ languageName: node
+ linkType: hard
+
+"emoji-regex@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "emoji-regex@npm:8.0.0"
+ checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010
+ languageName: node
+ linkType: hard
+
+"emoji-regex@npm:^9.2.2":
+ version: 9.2.2
+ resolution: "emoji-regex@npm:9.2.2"
+ checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639
+ languageName: node
+ linkType: hard
+
+"encoding@npm:^0.1.13":
+ version: 0.1.13
+ resolution: "encoding@npm:0.1.13"
+ dependencies:
+ iconv-lite: "npm:^0.6.2"
+ checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039
+ languageName: node
+ linkType: hard
+
+"enhanced-resolve@npm:^5.15.0, enhanced-resolve@npm:^5.17.1":
+ version: 5.17.1
+ resolution: "enhanced-resolve@npm:5.17.1"
+ dependencies:
+ graceful-fs: "npm:^4.2.4"
+ tapable: "npm:^2.2.0"
+ checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370
+ languageName: node
+ linkType: hard
+
+"entities@npm:^4.4.0":
+ version: 4.5.0
+ resolution: "entities@npm:4.5.0"
+ checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250
+ languageName: node
+ linkType: hard
+
+"env-paths@npm:^2.2.0":
+ version: 2.2.1
+ resolution: "env-paths@npm:2.2.1"
+ checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4
+ languageName: node
+ linkType: hard
+
+"err-code@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "err-code@npm:2.0.3"
+ checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66
+ languageName: node
+ linkType: hard
+
+"error-ex@npm:^1.3.1":
+ version: 1.3.2
+ resolution: "error-ex@npm:1.3.2"
+ dependencies:
+ is-arrayish: "npm:^0.2.1"
+ checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce
+ languageName: node
+ linkType: hard
+
+"es-module-lexer@npm:^1.5.4":
+ version: 1.5.4
+ resolution: "es-module-lexer@npm:1.5.4"
+ checksum: 10c0/300a469488c2f22081df1e4c8398c78db92358496e639b0df7f89ac6455462aaf5d8893939087c1a1cbcbf20eed4610c70e0bcb8f3e4b0d80a5d2611c539408c
+ languageName: node
+ linkType: hard
+
+"esbuild@npm:^0.21.3":
+ version: 0.21.5
+ resolution: "esbuild@npm:0.21.5"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.21.5"
+ "@esbuild/android-arm": "npm:0.21.5"
+ "@esbuild/android-arm64": "npm:0.21.5"
+ "@esbuild/android-x64": "npm:0.21.5"
+ "@esbuild/darwin-arm64": "npm:0.21.5"
+ "@esbuild/darwin-x64": "npm:0.21.5"
+ "@esbuild/freebsd-arm64": "npm:0.21.5"
+ "@esbuild/freebsd-x64": "npm:0.21.5"
+ "@esbuild/linux-arm": "npm:0.21.5"
+ "@esbuild/linux-arm64": "npm:0.21.5"
+ "@esbuild/linux-ia32": "npm:0.21.5"
+ "@esbuild/linux-loong64": "npm:0.21.5"
+ "@esbuild/linux-mips64el": "npm:0.21.5"
+ "@esbuild/linux-ppc64": "npm:0.21.5"
+ "@esbuild/linux-riscv64": "npm:0.21.5"
+ "@esbuild/linux-s390x": "npm:0.21.5"
+ "@esbuild/linux-x64": "npm:0.21.5"
+ "@esbuild/netbsd-x64": "npm:0.21.5"
+ "@esbuild/openbsd-x64": "npm:0.21.5"
+ "@esbuild/sunos-x64": "npm:0.21.5"
+ "@esbuild/win32-arm64": "npm:0.21.5"
+ "@esbuild/win32-ia32": "npm:0.21.5"
+ "@esbuild/win32-x64": "npm:0.21.5"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10c0/fa08508adf683c3f399e8a014a6382a6b65542213431e26206c0720e536b31c09b50798747c2a105a4bbba1d9767b8d3615a74c2f7bf1ddf6d836cd11eb672de
+ languageName: node
+ linkType: hard
+
+"esbuild@npm:^0.24.0":
+ version: 0.24.0
+ resolution: "esbuild@npm:0.24.0"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.24.0"
+ "@esbuild/android-arm": "npm:0.24.0"
+ "@esbuild/android-arm64": "npm:0.24.0"
+ "@esbuild/android-x64": "npm:0.24.0"
+ "@esbuild/darwin-arm64": "npm:0.24.0"
+ "@esbuild/darwin-x64": "npm:0.24.0"
+ "@esbuild/freebsd-arm64": "npm:0.24.0"
+ "@esbuild/freebsd-x64": "npm:0.24.0"
+ "@esbuild/linux-arm": "npm:0.24.0"
+ "@esbuild/linux-arm64": "npm:0.24.0"
+ "@esbuild/linux-ia32": "npm:0.24.0"
+ "@esbuild/linux-loong64": "npm:0.24.0"
+ "@esbuild/linux-mips64el": "npm:0.24.0"
+ "@esbuild/linux-ppc64": "npm:0.24.0"
+ "@esbuild/linux-riscv64": "npm:0.24.0"
+ "@esbuild/linux-s390x": "npm:0.24.0"
+ "@esbuild/linux-x64": "npm:0.24.0"
+ "@esbuild/netbsd-x64": "npm:0.24.0"
+ "@esbuild/openbsd-arm64": "npm:0.24.0"
+ "@esbuild/openbsd-x64": "npm:0.24.0"
+ "@esbuild/sunos-x64": "npm:0.24.0"
+ "@esbuild/win32-arm64": "npm:0.24.0"
+ "@esbuild/win32-ia32": "npm:0.24.0"
+ "@esbuild/win32-x64": "npm:0.24.0"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-arm64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10c0/9f1aadd8d64f3bff422ae78387e66e51a5e09de6935a6f987b6e4e189ed00fdc2d1bc03d2e33633b094008529c8b6e06c7ad1a9782fb09fec223bf95998c0683
+ languageName: node
+ linkType: hard
+
+"escalade@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "escalade@npm:3.2.0"
+ checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65
+ languageName: node
+ linkType: hard
+
+"escape-string-regexp@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "escape-string-regexp@npm:4.0.0"
+ checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9
+ languageName: node
+ linkType: hard
+
+"eslint-compat-utils@npm:^0.5.1":
+ version: 0.5.1
+ resolution: "eslint-compat-utils@npm:0.5.1"
+ dependencies:
+ semver: "npm:^7.5.4"
+ peerDependencies:
+ eslint: ">=6.0.0"
+ checksum: 10c0/325e815205fab70ebcd379f6d4b5d44c7d791bb8dfe0c9888233f30ebabd9418422595b53a781b946c768d9244d858540e5e6129a6b3dd6d606f467d599edc6c
+ languageName: node
+ linkType: hard
+
+"eslint-config-flat-gitignore@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "eslint-config-flat-gitignore@npm:0.3.0"
+ dependencies:
+ "@eslint/compat": "npm:^1.1.1"
+ find-up-simple: "npm:^1.0.0"
+ peerDependencies:
+ eslint: ^9.5.0
+ checksum: 10c0/0fd0f9c7839dec4adef633ee23c6c3aacd6edbdfc09f0f464e7d2c8e20abd514f7a6bd822fb21535f0532cf4abc49302d7334af21fcbfaedc5fbcdc8c5f1d169
+ languageName: node
+ linkType: hard
+
+"eslint-doc-generator@npm:^1.7.1":
+ version: 1.7.1
+ resolution: "eslint-doc-generator@npm:1.7.1"
+ dependencies:
+ "@typescript-eslint/utils": "npm:^5.38.1"
+ ajv: "npm:^8.11.2"
+ boolean: "npm:^3.2.0"
+ commander: "npm:^10.0.0"
+ cosmiconfig: "npm:^8.0.0"
+ deepmerge: "npm:^4.2.2"
+ dot-prop: "npm:^7.2.0"
+ jest-diff: "npm:^29.2.1"
+ json-schema-traverse: "npm:^1.0.0"
+ markdown-table: "npm:^3.0.3"
+ no-case: "npm:^3.0.4"
+ type-fest: "npm:^3.0.0"
+ peerDependencies:
+ eslint: ">= 7"
+ bin:
+ eslint-doc-generator: dist/bin/eslint-doc-generator.js
+ checksum: 10c0/91d7eb0d72536a346e56951ea5e3217093331830a4511e223a32ba39d7f588e9d148065721900b11e7e3d0bfff58f902f9a576970fe70df7e4e2f0f23e8d425c
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-node@npm:^0.3.9":
+ version: 0.3.9
+ resolution: "eslint-import-resolver-node@npm:0.3.9"
+ dependencies:
+ debug: "npm:^3.2.7"
+ is-core-module: "npm:^2.13.0"
+ resolve: "npm:^1.22.4"
+ checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-typescript@npm:^3.6.3":
+ version: 3.6.3
+ resolution: "eslint-import-resolver-typescript@npm:3.6.3"
+ dependencies:
+ "@nolyfill/is-core-module": "npm:1.0.39"
+ debug: "npm:^4.3.5"
+ enhanced-resolve: "npm:^5.15.0"
+ eslint-module-utils: "npm:^2.8.1"
+ fast-glob: "npm:^3.3.2"
+ get-tsconfig: "npm:^4.7.5"
+ is-bun-module: "npm:^1.0.2"
+ is-glob: "npm:^4.0.3"
+ peerDependencies:
+ eslint: "*"
+ eslint-plugin-import: "*"
+ eslint-plugin-import-x: "*"
+ peerDependenciesMeta:
+ eslint-plugin-import:
+ optional: true
+ eslint-plugin-import-x:
+ optional: true
+ checksum: 10c0/5933b00791b7b077725b9ba9a85327d2e2dc7c8944c18a868feb317a0bf0e1e77aed2254c9c5e24dcc49360d119331d2c15281837f4269592965ace380a75111
+ languageName: node
+ linkType: hard
+
+"eslint-module-utils@npm:^2.8.1":
+ version: 2.12.0
+ resolution: "eslint-module-utils@npm:2.12.0"
+ dependencies:
+ debug: "npm:^3.2.7"
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10c0/4d8b46dcd525d71276f9be9ffac1d2be61c9d54cc53c992e6333cf957840dee09381842b1acbbb15fc6b255ebab99cd481c5007ab438e5455a14abe1a0468558
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-es-x@npm:^7.8.0":
+ version: 7.8.0
+ resolution: "eslint-plugin-es-x@npm:7.8.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.1.2"
+ "@eslint-community/regexpp": "npm:^4.11.0"
+ eslint-compat-utils: "npm:^0.5.1"
+ peerDependencies:
+ eslint: ">=8"
+ checksum: 10c0/002fda8c029bc5da41e24e7ac11654062831d675fc4f5f20d0de460e24bf1e05cd559000678ef3e46c48641190f4fc07ae3d57aa5e8b085ef5f67e5f63742614
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-eslint-plugin@npm:^6.3.2":
+ version: 6.3.2
+ resolution: "eslint-plugin-eslint-plugin@npm:6.3.2"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.4.0"
+ estraverse: "npm:^5.3.0"
+ peerDependencies:
+ eslint: ">=8.23.0"
+ checksum: 10c0/e73bd86d3888c3c6464228cfc1c05d9f2591d5d3472482ce55fcfa5819edcb40002b4ab1fdebf4408f720ac93a32c666fdc91723f9ddb986a3434beb8e6515cf
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-import-x@npm:^4.4.2":
+ version: 4.4.2
+ resolution: "eslint-plugin-import-x@npm:4.4.2"
+ dependencies:
+ "@typescript-eslint/utils": "npm:^8.1.0"
+ debug: "npm:^4.3.4"
+ doctrine: "npm:^3.0.0"
+ eslint-import-resolver-node: "npm:^0.3.9"
+ get-tsconfig: "npm:^4.7.3"
+ is-glob: "npm:^4.0.3"
+ minimatch: "npm:^9.0.3"
+ semver: "npm:^7.6.3"
+ stable-hash: "npm:^0.0.4"
+ tslib: "npm:^2.6.3"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ checksum: 10c0/0c7ac5e5390f30178d78f7380ba55cfa23fa150f1e49b313e4ed787ff760dac65f1a250eb261768b2f6d6cdd16cc0d95a7874da213e43a849a747e30b4108cf2
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-n@npm:^17.14.0":
+ version: 17.14.0
+ resolution: "eslint-plugin-n@npm:17.14.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.4.1"
+ enhanced-resolve: "npm:^5.17.1"
+ eslint-plugin-es-x: "npm:^7.8.0"
+ get-tsconfig: "npm:^4.8.1"
+ globals: "npm:^15.11.0"
+ ignore: "npm:^5.3.2"
+ minimatch: "npm:^9.0.5"
+ semver: "npm:^7.6.3"
+ peerDependencies:
+ eslint: ">=8.23.0"
+ checksum: 10c0/ad46415e0a31431dd9c6996b6497d48dd891bf034b1880d55e292c60434022fa0ac4d74734bb08dc204200fe3947b47fac2d8300d319bd650175c0fffc62c609
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-rxjs-x@workspace:.":
+ version: 0.0.0-use.local
+ resolution: "eslint-plugin-rxjs-x@workspace:."
+ dependencies:
+ "@eslint/js": "npm:^9.16.0"
+ "@stylistic/eslint-plugin": "npm:^2.11.0"
+ "@types/common-tags": "npm:^1.8.4"
+ "@types/node": "npm:~18.18.0"
+ "@typescript-eslint/rule-tester": "npm:^8.17.0"
+ "@typescript-eslint/scope-manager": "npm:^8.1.0"
+ "@typescript-eslint/utils": "npm:^8.1.0"
+ "@typescript/vfs": "npm:^1.6.0"
+ "@vitest/coverage-v8": "npm:^2.1.8"
+ "@vitest/eslint-plugin": "npm:^1.1.14"
+ bumpp: "npm:^9.8.1"
+ common-tags: "npm:^1.8.0"
+ decamelize: "npm:^5.0.1"
+ eslint: "npm:^9.16.0"
+ eslint-config-flat-gitignore: "npm:^0.3.0"
+ eslint-doc-generator: "npm:^1.7.1"
+ eslint-import-resolver-typescript: "npm:^3.6.3"
+ eslint-plugin-eslint-plugin: "npm:^6.3.2"
+ eslint-plugin-import-x: "npm:^4.4.2"
+ eslint-plugin-n: "npm:^17.14.0"
+ markdownlint-cli2: "npm:^0.15.0"
+ rxjs: "npm:^7.8.1"
+ ts-api-utils: "npm:^1.3.0"
+ tslib: "npm:^2.1.0"
+ tsup: "npm:^8.3.5"
+ typescript: "npm:~5.7.2"
+ typescript-eslint: "npm:^8.17.0"
+ vitest: "npm:^2.1.8"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ rxjs: ">=7.2.0"
+ typescript: ">=4.7.4"
+ peerDependenciesMeta:
+ rxjs:
+ optional: true
+ languageName: unknown
+ linkType: soft
+
+"eslint-scope@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "eslint-scope@npm:5.1.1"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^4.1.1"
+ checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a
+ languageName: node
+ linkType: hard
+
+"eslint-scope@npm:^8.2.0":
+ version: 8.2.0
+ resolution: "eslint-scope@npm:8.2.0"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/8d2d58e2136d548ac7e0099b1a90d9fab56f990d86eb518de1247a7066d38c908be2f3df477a79cf60d70b30ba18735d6c6e70e9914dca2ee515a729975d70d6
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.3":
+ version: 3.4.3
+ resolution: "eslint-visitor-keys@npm:3.4.3"
+ checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "eslint-visitor-keys@npm:4.2.0"
+ checksum: 10c0/2ed81c663b147ca6f578312919483eb040295bbab759e5a371953456c636c5b49a559883e2677112453728d66293c0a4c90ab11cab3428cf02a0236d2e738269
+ languageName: node
+ linkType: hard
+
+"eslint@npm:^9.16.0":
+ version: 9.16.0
+ resolution: "eslint@npm:9.16.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@eslint-community/regexpp": "npm:^4.12.1"
+ "@eslint/config-array": "npm:^0.19.0"
+ "@eslint/core": "npm:^0.9.0"
+ "@eslint/eslintrc": "npm:^3.2.0"
+ "@eslint/js": "npm:9.16.0"
+ "@eslint/plugin-kit": "npm:^0.2.3"
+ "@humanfs/node": "npm:^0.16.6"
+ "@humanwhocodes/module-importer": "npm:^1.0.1"
+ "@humanwhocodes/retry": "npm:^0.4.1"
+ "@types/estree": "npm:^1.0.6"
+ "@types/json-schema": "npm:^7.0.15"
+ ajv: "npm:^6.12.4"
+ chalk: "npm:^4.0.0"
+ cross-spawn: "npm:^7.0.5"
+ debug: "npm:^4.3.2"
+ escape-string-regexp: "npm:^4.0.0"
+ eslint-scope: "npm:^8.2.0"
+ eslint-visitor-keys: "npm:^4.2.0"
+ espree: "npm:^10.3.0"
+ esquery: "npm:^1.5.0"
+ esutils: "npm:^2.0.2"
+ fast-deep-equal: "npm:^3.1.3"
+ file-entry-cache: "npm:^8.0.0"
+ find-up: "npm:^5.0.0"
+ glob-parent: "npm:^6.0.2"
+ ignore: "npm:^5.2.0"
+ imurmurhash: "npm:^0.1.4"
+ is-glob: "npm:^4.0.0"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ lodash.merge: "npm:^4.6.2"
+ minimatch: "npm:^3.1.2"
+ natural-compare: "npm:^1.4.0"
+ optionator: "npm:^0.9.3"
+ peerDependencies:
+ jiti: "*"
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ bin:
+ eslint: bin/eslint.js
+ checksum: 10c0/f36d12652c6f20bab8a77375b8ad29a6af030c3840deb0a5f9dd4cee49d68a2d68d7dc73b0c25918df59d83cd686dd5712e11387e696e1f3842e8dde15cd3255
+ languageName: node
+ linkType: hard
+
+"espree@npm:^10.0.1, espree@npm:^10.3.0":
+ version: 10.3.0
+ resolution: "espree@npm:10.3.0"
+ dependencies:
+ acorn: "npm:^8.14.0"
+ acorn-jsx: "npm:^5.3.2"
+ eslint-visitor-keys: "npm:^4.2.0"
+ checksum: 10c0/272beeaca70d0a1a047d61baff64db04664a33d7cfb5d144f84bc8a5c6194c6c8ebe9cc594093ca53add88baa23e59b01e69e8a0160ab32eac570482e165c462
+ languageName: node
+ linkType: hard
+
+"esquery@npm:^1.5.0":
+ version: 1.6.0
+ resolution: "esquery@npm:1.6.0"
+ dependencies:
+ estraverse: "npm:^5.1.0"
+ checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2
+ languageName: node
+ linkType: hard
+
+"esrecurse@npm:^4.3.0":
+ version: 4.3.0
+ resolution: "esrecurse@npm:4.3.0"
+ dependencies:
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5
+ languageName: node
+ linkType: hard
+
+"estraverse@npm:^4.1.1":
+ version: 4.3.0
+ resolution: "estraverse@npm:4.3.0"
+ checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d
+ languageName: node
+ linkType: hard
+
+"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
+ version: 5.3.0
+ resolution: "estraverse@npm:5.3.0"
+ checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107
+ languageName: node
+ linkType: hard
+
+"estree-walker@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "estree-walker@npm:3.0.3"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d
+ languageName: node
+ linkType: hard
+
+"esutils@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "esutils@npm:2.0.3"
+ checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7
+ languageName: node
+ linkType: hard
+
+"execa@npm:^8.0.1":
+ version: 8.0.1
+ resolution: "execa@npm:8.0.1"
+ dependencies:
+ cross-spawn: "npm:^7.0.3"
+ get-stream: "npm:^8.0.1"
+ human-signals: "npm:^5.0.0"
+ is-stream: "npm:^3.0.0"
+ merge-stream: "npm:^2.0.0"
+ npm-run-path: "npm:^5.1.0"
+ onetime: "npm:^6.0.0"
+ signal-exit: "npm:^4.1.0"
+ strip-final-newline: "npm:^3.0.0"
+ checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af
+ languageName: node
+ linkType: hard
+
+"expect-type@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "expect-type@npm:1.1.0"
+ checksum: 10c0/5af0febbe8fe18da05a6d51e3677adafd75213512285408156b368ca471252565d5ca6e59e4bddab25121f3cfcbbebc6a5489f8cc9db131cc29e69dcdcc7ae15
+ languageName: node
+ linkType: hard
+
+"exponential-backoff@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "exponential-backoff@npm:3.1.1"
+ checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579
+ languageName: node
+ linkType: hard
+
+"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "fast-deep-equal@npm:3.1.3"
+ checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0
+ languageName: node
+ linkType: hard
+
+"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2":
+ version: 3.3.2
+ resolution: "fast-glob@npm:3.3.2"
+ dependencies:
+ "@nodelib/fs.stat": "npm:^2.0.2"
+ "@nodelib/fs.walk": "npm:^1.2.3"
+ glob-parent: "npm:^5.1.2"
+ merge2: "npm:^1.3.0"
+ micromatch: "npm:^4.0.4"
+ checksum: 10c0/42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845
+ languageName: node
+ linkType: hard
+
+"fast-json-stable-stringify@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "fast-json-stable-stringify@npm:2.1.0"
+ checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b
+ languageName: node
+ linkType: hard
+
+"fast-levenshtein@npm:^2.0.6":
+ version: 2.0.6
+ resolution: "fast-levenshtein@npm:2.0.6"
+ checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4
+ languageName: node
+ linkType: hard
+
+"fast-uri@npm:^3.0.1":
+ version: 3.0.3
+ resolution: "fast-uri@npm:3.0.3"
+ checksum: 10c0/4b2c5ce681a062425eae4f15cdc8fc151fd310b2f69b1f96680677820a8b49c3cd6e80661a406e19d50f0c40a3f8bffdd458791baf66f4a879d80be28e10a320
+ languageName: node
+ linkType: hard
+
+"fastq@npm:^1.6.0":
+ version: 1.13.0
+ resolution: "fastq@npm:1.13.0"
+ dependencies:
+ reusify: "npm:^1.0.4"
+ checksum: 10c0/76c7b5dafb93c7e74359a3e6de834ce7a7c2e3a3184050ed4cb652661de55cf8d4895178d8d3ccd23069395056c7bb15450660d38fb382ca88c142b22694d7c9
+ languageName: node
+ linkType: hard
+
+"fdir@npm:^6.4.2":
+ version: 6.4.2
+ resolution: "fdir@npm:6.4.2"
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+ checksum: 10c0/34829886f34a3ca4170eca7c7180ec4de51a3abb4d380344063c0ae2e289b11d2ba8b724afee974598c83027fea363ff598caf2b51bc4e6b1e0d8b80cc530573
+ languageName: node
+ linkType: hard
+
+"file-entry-cache@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "file-entry-cache@npm:8.0.0"
+ dependencies:
+ flat-cache: "npm:^4.0.0"
+ checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638
+ languageName: node
+ linkType: hard
+
+"fill-range@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "fill-range@npm:7.1.1"
+ dependencies:
+ to-regex-range: "npm:^5.0.1"
+ checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018
+ languageName: node
+ linkType: hard
+
+"find-up-simple@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "find-up-simple@npm:1.0.0"
+ checksum: 10c0/de1ad5e55c8c162f5600fe3297bb55a3da5cd9cb8c6755e463ec1d52c4c15a84e312a68397fb5962d13263b3dbd4ea294668c465ccacc41291d7cc97588769f9
+ languageName: node
+ linkType: hard
+
+"find-up@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "find-up@npm:5.0.0"
+ dependencies:
+ locate-path: "npm:^6.0.0"
+ path-exists: "npm:^4.0.0"
+ checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a
+ languageName: node
+ linkType: hard
+
+"flat-cache@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "flat-cache@npm:4.0.1"
+ dependencies:
+ flatted: "npm:^3.2.9"
+ keyv: "npm:^4.5.4"
+ checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc
+ languageName: node
+ linkType: hard
+
+"flatted@npm:^3.2.9":
+ version: 3.3.1
+ resolution: "flatted@npm:3.3.1"
+ checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf
+ languageName: node
+ linkType: hard
+
+"foreground-child@npm:^3.1.0":
+ version: 3.3.0
+ resolution: "foreground-child@npm:3.3.0"
+ dependencies:
+ cross-spawn: "npm:^7.0.0"
+ signal-exit: "npm:^4.0.1"
+ checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2
+ languageName: node
+ linkType: hard
+
+"fs-minipass@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "fs-minipass@npm:2.1.0"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004
+ languageName: node
+ linkType: hard
+
+"fs-minipass@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "fs-minipass@npm:3.0.3"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94
+ languageName: node
+ linkType: hard
+
+"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3":
+ version: 2.3.3
+ resolution: "fsevents@npm:2.3.3"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
+ version: 2.3.3
+ resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1"
+ dependencies:
+ node-gyp: "npm:latest"
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"function-bind@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "function-bind@npm:1.1.2"
+ checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5
+ languageName: node
+ linkType: hard
+
+"get-stream@npm:^8.0.1":
+ version: 8.0.1
+ resolution: "get-stream@npm:8.0.1"
+ checksum: 10c0/5c2181e98202b9dae0bb4a849979291043e5892eb40312b47f0c22b9414fc9b28a3b6063d2375705eb24abc41ecf97894d9a51f64ff021511b504477b27b4290
+ languageName: node
+ linkType: hard
+
+"get-tsconfig@npm:^4.7.3, get-tsconfig@npm:^4.7.5, get-tsconfig@npm:^4.8.1":
+ version: 4.8.1
+ resolution: "get-tsconfig@npm:4.8.1"
+ dependencies:
+ resolve-pkg-maps: "npm:^1.0.0"
+ checksum: 10c0/536ee85d202f604f4b5fb6be81bcd6e6d9a96846811e83e9acc6de4a04fb49506edea0e1b8cf1d5ee7af33e469916ec2809d4c5445ab8ae015a7a51fbd1572f9
+ languageName: node
+ linkType: hard
+
+"giget@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "giget@npm:1.2.3"
+ dependencies:
+ citty: "npm:^0.1.6"
+ consola: "npm:^3.2.3"
+ defu: "npm:^6.1.4"
+ node-fetch-native: "npm:^1.6.3"
+ nypm: "npm:^0.3.8"
+ ohash: "npm:^1.1.3"
+ pathe: "npm:^1.1.2"
+ tar: "npm:^6.2.0"
+ bin:
+ giget: dist/cli.mjs
+ checksum: 10c0/0e82836783c704346fdda83e23d144e97f28a959320b1d8ee73c69a5af562362bcb727cf6ad99f90e45ed8a6abec140833534bb1fedcaa1c06fa026daaf3119c
+ languageName: node
+ linkType: hard
+
+"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2":
+ version: 5.1.2
+ resolution: "glob-parent@npm:5.1.2"
+ dependencies:
+ is-glob: "npm:^4.0.1"
+ checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee
+ languageName: node
+ linkType: hard
+
+"glob-parent@npm:^6.0.2":
+ version: 6.0.2
+ resolution: "glob-parent@npm:6.0.2"
+ dependencies:
+ is-glob: "npm:^4.0.3"
+ checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8
+ languageName: node
+ linkType: hard
+
+"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.4.1":
+ version: 10.4.5
+ resolution: "glob@npm:10.4.5"
+ dependencies:
+ foreground-child: "npm:^3.1.0"
+ jackspeak: "npm:^3.1.2"
+ minimatch: "npm:^9.0.4"
+ minipass: "npm:^7.1.2"
+ package-json-from-dist: "npm:^1.0.0"
+ path-scurry: "npm:^1.11.1"
+ bin:
+ glob: dist/esm/bin.mjs
+ checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e
+ languageName: node
+ linkType: hard
+
+"globals@npm:^14.0.0":
+ version: 14.0.0
+ resolution: "globals@npm:14.0.0"
+ checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d
+ languageName: node
+ linkType: hard
+
+"globals@npm:^15.11.0":
+ version: 15.11.0
+ resolution: "globals@npm:15.11.0"
+ checksum: 10c0/861e39bb6bd9bd1b9f355c25c962e5eb4b3f0e1567cf60fa6c06e8c502b0ec8706b1cce055d69d84d0b7b8e028bec5418cf629a54e7047e116538d1c1c1a375c
+ languageName: node
+ linkType: hard
+
+"globby@npm:14.0.2":
+ version: 14.0.2
+ resolution: "globby@npm:14.0.2"
+ dependencies:
+ "@sindresorhus/merge-streams": "npm:^2.1.0"
+ fast-glob: "npm:^3.3.2"
+ ignore: "npm:^5.2.4"
+ path-type: "npm:^5.0.0"
+ slash: "npm:^5.1.0"
+ unicorn-magic: "npm:^0.1.0"
+ checksum: 10c0/3f771cd683b8794db1e7ebc8b6b888d43496d93a82aad4e9d974620f578581210b6c5a6e75ea29573ed16a1345222fab6e9b877a8d1ed56eeb147e09f69c6f78
+ languageName: node
+ linkType: hard
+
+"globby@npm:^11.1.0":
+ version: 11.1.0
+ resolution: "globby@npm:11.1.0"
+ dependencies:
+ array-union: "npm:^2.1.0"
+ dir-glob: "npm:^3.0.1"
+ fast-glob: "npm:^3.2.9"
+ ignore: "npm:^5.2.0"
+ merge2: "npm:^1.4.1"
+ slash: "npm:^3.0.0"
+ checksum: 10c0/b39511b4afe4bd8a7aead3a27c4ade2b9968649abab0a6c28b1a90141b96ca68ca5db1302f7c7bd29eab66bf51e13916b8e0a3d0ac08f75e1e84a39b35691189
+ languageName: node
+ linkType: hard
+
+"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6":
+ version: 4.2.11
+ resolution: "graceful-fs@npm:4.2.11"
+ checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2
+ languageName: node
+ linkType: hard
+
+"graphemer@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "graphemer@npm:1.4.0"
+ checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31
+ languageName: node
+ linkType: hard
+
+"has-flag@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "has-flag@npm:4.0.0"
+ checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1
+ languageName: node
+ linkType: hard
+
+"hasown@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "hasown@npm:2.0.2"
+ dependencies:
+ function-bind: "npm:^1.1.2"
+ checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9
+ languageName: node
+ linkType: hard
+
+"html-escaper@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "html-escaper@npm:2.0.2"
+ checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0
+ languageName: node
+ linkType: hard
+
+"http-cache-semantics@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "http-cache-semantics@npm:4.1.1"
+ checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc
+ languageName: node
+ linkType: hard
+
+"http-proxy-agent@npm:^7.0.0":
+ version: 7.0.2
+ resolution: "http-proxy-agent@npm:7.0.2"
+ dependencies:
+ agent-base: "npm:^7.1.0"
+ debug: "npm:^4.3.4"
+ checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921
+ languageName: node
+ linkType: hard
+
+"https-proxy-agent@npm:^7.0.1":
+ version: 7.0.5
+ resolution: "https-proxy-agent@npm:7.0.5"
+ dependencies:
+ agent-base: "npm:^7.0.2"
+ debug: "npm:4"
+ checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c
+ languageName: node
+ linkType: hard
+
+"human-signals@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "human-signals@npm:5.0.0"
+ checksum: 10c0/5a9359073fe17a8b58e5a085e9a39a950366d9f00217c4ff5878bd312e09d80f460536ea6a3f260b5943a01fe55c158d1cea3fc7bee3d0520aeef04f6d915c82
+ languageName: node
+ linkType: hard
+
+"iconv-lite@npm:^0.6.2":
+ version: 0.6.3
+ resolution: "iconv-lite@npm:0.6.3"
+ dependencies:
+ safer-buffer: "npm:>= 2.1.2 < 3.0.0"
+ checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1
+ languageName: node
+ linkType: hard
+
+"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1, ignore@npm:^5.3.2":
+ version: 5.3.2
+ resolution: "ignore@npm:5.3.2"
+ checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
+ languageName: node
+ linkType: hard
+
+"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0":
+ version: 3.3.0
+ resolution: "import-fresh@npm:3.3.0"
+ dependencies:
+ parent-module: "npm:^1.0.0"
+ resolve-from: "npm:^4.0.0"
+ checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3
+ languageName: node
+ linkType: hard
+
+"imurmurhash@npm:^0.1.4":
+ version: 0.1.4
+ resolution: "imurmurhash@npm:0.1.4"
+ checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6
+ languageName: node
+ linkType: hard
+
+"indent-string@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "indent-string@npm:4.0.0"
+ checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f
+ languageName: node
+ linkType: hard
+
+"ip-address@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "ip-address@npm:9.0.5"
+ dependencies:
+ jsbn: "npm:1.1.0"
+ sprintf-js: "npm:^1.1.3"
+ checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc
+ languageName: node
+ linkType: hard
+
+"is-arrayish@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "is-arrayish@npm:0.2.1"
+ checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729
+ languageName: node
+ linkType: hard
+
+"is-binary-path@npm:~2.1.0":
+ version: 2.1.0
+ resolution: "is-binary-path@npm:2.1.0"
+ dependencies:
+ binary-extensions: "npm:^2.0.0"
+ checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38
+ languageName: node
+ linkType: hard
+
+"is-bun-module@npm:^1.0.2":
+ version: 1.2.1
+ resolution: "is-bun-module@npm:1.2.1"
+ dependencies:
+ semver: "npm:^7.6.3"
+ checksum: 10c0/819e63cd4468265a3e89cdc241554e37aeb85e40375a56dd559c022f4395491273267a0f843274fda6cad1eac3b0f8dc6d9e06cc349e33e2bf45098761184736
+ languageName: node
+ linkType: hard
+
+"is-core-module@npm:^2.13.0":
+ version: 2.15.1
+ resolution: "is-core-module@npm:2.15.1"
+ dependencies:
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/53432f10c69c40bfd2fa8914133a68709ff9498c86c3bf5fca3cdf3145a56fd2168cbf4a43b29843a6202a120a5f9c5ffba0a4322e1e3441739bc0b641682612
+ languageName: node
+ linkType: hard
+
+"is-extglob@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "is-extglob@npm:2.1.1"
+ checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912
+ languageName: node
+ linkType: hard
+
+"is-fullwidth-code-point@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "is-fullwidth-code-point@npm:3.0.0"
+ checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc
+ languageName: node
+ linkType: hard
+
+"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1":
+ version: 4.0.3
+ resolution: "is-glob@npm:4.0.3"
+ dependencies:
+ is-extglob: "npm:^2.1.1"
+ checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a
+ languageName: node
+ linkType: hard
+
+"is-lambda@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "is-lambda@npm:1.0.1"
+ checksum: 10c0/85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d
+ languageName: node
+ linkType: hard
+
+"is-number@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "is-number@npm:7.0.0"
+ checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811
+ languageName: node
+ linkType: hard
+
+"is-stream@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "is-stream@npm:3.0.0"
+ checksum: 10c0/eb2f7127af02ee9aa2a0237b730e47ac2de0d4e76a4a905a50a11557f2339df5765eaea4ceb8029f1efa978586abe776908720bfcb1900c20c6ec5145f6f29d8
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "isexe@npm:2.0.0"
+ checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "isexe@npm:3.1.1"
+ checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7
+ languageName: node
+ linkType: hard
+
+"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.2":
+ version: 3.2.2
+ resolution: "istanbul-lib-coverage@npm:3.2.2"
+ checksum: 10c0/6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b
+ languageName: node
+ linkType: hard
+
+"istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "istanbul-lib-report@npm:3.0.1"
+ dependencies:
+ istanbul-lib-coverage: "npm:^3.0.0"
+ make-dir: "npm:^4.0.0"
+ supports-color: "npm:^7.1.0"
+ checksum: 10c0/84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7
+ languageName: node
+ linkType: hard
+
+"istanbul-lib-source-maps@npm:^5.0.6":
+ version: 5.0.6
+ resolution: "istanbul-lib-source-maps@npm:5.0.6"
+ dependencies:
+ "@jridgewell/trace-mapping": "npm:^0.3.23"
+ debug: "npm:^4.1.1"
+ istanbul-lib-coverage: "npm:^3.0.0"
+ checksum: 10c0/ffe75d70b303a3621ee4671554f306e0831b16f39ab7f4ab52e54d356a5d33e534d97563e318f1333a6aae1d42f91ec49c76b6cd3f3fb378addcb5c81da0255f
+ languageName: node
+ linkType: hard
+
+"istanbul-reports@npm:^3.1.7":
+ version: 3.1.7
+ resolution: "istanbul-reports@npm:3.1.7"
+ dependencies:
+ html-escaper: "npm:^2.0.0"
+ istanbul-lib-report: "npm:^3.0.0"
+ checksum: 10c0/a379fadf9cf8dc5dfe25568115721d4a7eb82fbd50b005a6672aff9c6989b20cc9312d7865814e0859cd8df58cbf664482e1d3604be0afde1f7fc3ccc1394a51
+ languageName: node
+ linkType: hard
+
+"jackspeak@npm:^3.1.2":
+ version: 3.4.3
+ resolution: "jackspeak@npm:3.4.3"
+ dependencies:
+ "@isaacs/cliui": "npm:^8.0.2"
+ "@pkgjs/parseargs": "npm:^0.11.0"
+ dependenciesMeta:
+ "@pkgjs/parseargs":
+ optional: true
+ checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9
+ languageName: node
+ linkType: hard
+
+"jest-diff@npm:^29.2.1":
+ version: 29.7.0
+ resolution: "jest-diff@npm:29.7.0"
+ dependencies:
+ chalk: "npm:^4.0.0"
+ diff-sequences: "npm:^29.6.3"
+ jest-get-type: "npm:^29.6.3"
+ pretty-format: "npm:^29.7.0"
+ checksum: 10c0/89a4a7f182590f56f526443dde69acefb1f2f0c9e59253c61d319569856c4931eae66b8a3790c443f529267a0ddba5ba80431c585deed81827032b2b2a1fc999
+ languageName: node
+ linkType: hard
+
+"jest-get-type@npm:^29.6.3":
+ version: 29.6.3
+ resolution: "jest-get-type@npm:29.6.3"
+ checksum: 10c0/552e7a97a983d3c2d4e412a44eb7de0430ff773dd99f7500962c268d6dfbfa431d7d08f919c9d960530e5f7f78eb47f267ad9b318265e5092b3ff9ede0db7c2b
+ languageName: node
+ linkType: hard
+
+"jiti@npm:^1.21.6":
+ version: 1.21.6
+ resolution: "jiti@npm:1.21.6"
+ bin:
+ jiti: bin/jiti.js
+ checksum: 10c0/05b9ed58cd30d0c3ccd3c98209339e74f50abd9a17e716f65db46b6a35812103f6bde6e134be7124d01745586bca8cc5dae1d0d952267c3ebe55171949c32e56
+ languageName: node
+ linkType: hard
+
+"joycon@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "joycon@npm:3.1.1"
+ checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae
+ languageName: node
+ linkType: hard
+
+"js-tokens@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "js-tokens@npm:4.0.0"
+ checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
+ languageName: node
+ linkType: hard
+
+"js-yaml@npm:4.1.0, js-yaml@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "js-yaml@npm:4.1.0"
+ dependencies:
+ argparse: "npm:^2.0.1"
+ bin:
+ js-yaml: bin/js-yaml.js
+ checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f
+ languageName: node
+ linkType: hard
+
+"jsbn@npm:1.1.0":
+ version: 1.1.0
+ resolution: "jsbn@npm:1.1.0"
+ checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96
+ languageName: node
+ linkType: hard
+
+"json-buffer@npm:3.0.1":
+ version: 3.0.1
+ resolution: "json-buffer@npm:3.0.1"
+ checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7
+ languageName: node
+ linkType: hard
+
+"json-parse-even-better-errors@npm:^2.3.0":
+ version: 2.3.1
+ resolution: "json-parse-even-better-errors@npm:2.3.1"
+ checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3
+ languageName: node
+ linkType: hard
+
+"json-schema-traverse@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "json-schema-traverse@npm:0.4.1"
+ checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce
+ languageName: node
+ linkType: hard
+
+"json-schema-traverse@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "json-schema-traverse@npm:1.0.0"
+ checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6
+ languageName: node
+ linkType: hard
+
+"json-stable-stringify-without-jsonify@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
+ checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5
+ languageName: node
+ linkType: hard
+
+"jsonc-parser@npm:3.3.1, jsonc-parser@npm:^3.3.1":
+ version: 3.3.1
+ resolution: "jsonc-parser@npm:3.3.1"
+ checksum: 10c0/269c3ae0a0e4f907a914bf334306c384aabb9929bd8c99f909275ebd5c2d3bc70b9bcd119ad794f339dec9f24b6a4ee9cd5a8ab2e6435e730ad4075388fc2ab6
+ languageName: node
+ linkType: hard
+
+"keyv@npm:^4.5.4":
+ version: 4.5.4
+ resolution: "keyv@npm:4.5.4"
+ dependencies:
+ json-buffer: "npm:3.0.1"
+ checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e
+ languageName: node
+ linkType: hard
+
+"kleur@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "kleur@npm:3.0.3"
+ checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b
+ languageName: node
+ linkType: hard
+
+"levn@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "levn@npm:0.4.1"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:~0.4.0"
+ checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e
+ languageName: node
+ linkType: hard
+
+"lilconfig@npm:^3.1.1":
+ version: 3.1.2
+ resolution: "lilconfig@npm:3.1.2"
+ checksum: 10c0/f059630b1a9bddaeba83059db00c672b64dc14074e9f232adce32b38ca1b5686ab737eb665c5ba3c32f147f0002b4bee7311ad0386a9b98547b5623e87071fbe
+ languageName: node
+ linkType: hard
+
+"lines-and-columns@npm:^1.1.6":
+ version: 1.2.4
+ resolution: "lines-and-columns@npm:1.2.4"
+ checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d
+ languageName: node
+ linkType: hard
+
+"linkify-it@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "linkify-it@npm:5.0.0"
+ dependencies:
+ uc.micro: "npm:^2.0.0"
+ checksum: 10c0/ff4abbcdfa2003472fc3eb4b8e60905ec97718e11e33cca52059919a4c80cc0e0c2a14d23e23d8c00e5402bc5a885cdba8ca053a11483ab3cc8b3c7a52f88e2d
+ languageName: node
+ linkType: hard
+
+"load-tsconfig@npm:^0.2.3":
+ version: 0.2.5
+ resolution: "load-tsconfig@npm:0.2.5"
+ checksum: 10c0/bf2823dd26389d3497b6567f07435c5a7a58d9df82e879b0b3892f87d8db26900f84c85bc329ef41c0540c0d6a448d1c23ddc64a80f3ff6838b940f3915a3fcb
+ languageName: node
+ linkType: hard
+
+"locate-path@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "locate-path@npm:6.0.0"
+ dependencies:
+ p-locate: "npm:^5.0.0"
+ checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3
+ languageName: node
+ linkType: hard
+
+"lodash.merge@npm:4.6.2, lodash.merge@npm:^4.6.2":
+ version: 4.6.2
+ resolution: "lodash.merge@npm:4.6.2"
+ checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506
+ languageName: node
+ linkType: hard
+
+"lodash.sortby@npm:^4.7.0":
+ version: 4.7.0
+ resolution: "lodash.sortby@npm:4.7.0"
+ checksum: 10c0/fc48fb54ff7669f33bb32997cab9460757ee99fafaf72400b261c3e10fde21538e47d8cfcbe6a25a31bcb5b7b727c27d52626386fc2de24eb059a6d64a89cdf5
+ languageName: node
+ linkType: hard
+
+"loupe@npm:^3.1.0, loupe@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "loupe@npm:3.1.2"
+ checksum: 10c0/b13c02e3ddd6a9d5f8bf84133b3242de556512d824dddeea71cce2dbd6579c8f4d672381c4e742d45cf4423d0701765b4a6e5fbc24701def16bc2b40f8daa96a
+ languageName: node
+ linkType: hard
+
+"lower-case@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "lower-case@npm:2.0.2"
+ dependencies:
+ tslib: "npm:^2.0.3"
+ checksum: 10c0/3d925e090315cf7dc1caa358e0477e186ffa23947740e4314a7429b6e62d72742e0bbe7536a5ae56d19d7618ce998aba05caca53c2902bd5742fdca5fc57fd7b
+ languageName: node
+ linkType: hard
+
+"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
+ version: 10.4.3
+ resolution: "lru-cache@npm:10.4.3"
+ checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb
+ languageName: node
+ linkType: hard
+
+"magic-string@npm:^0.30.12":
+ version: 0.30.12
+ resolution: "magic-string@npm:0.30.12"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.0"
+ checksum: 10c0/469f457d18af37dfcca8617086ea8a65bcd8b60ba8a1182cb024ce43e470ace3c9d1cb6bee58d3b311768fb16bc27bd50bdeebcaa63dadd0fd46cac4d2e11d5f
+ languageName: node
+ linkType: hard
+
+"magicast@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "magicast@npm:0.3.5"
+ dependencies:
+ "@babel/parser": "npm:^7.25.4"
+ "@babel/types": "npm:^7.25.4"
+ source-map-js: "npm:^1.2.0"
+ checksum: 10c0/a6cacc0a848af84f03e3f5bda7b0de75e4d0aa9ddce5517fd23ed0f31b5ddd51b2d0ff0b7e09b51f7de0f4053c7a1107117edda6b0732dca3e9e39e6c5a68c64
+ languageName: node
+ linkType: hard
+
+"make-dir@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "make-dir@npm:4.0.0"
+ dependencies:
+ semver: "npm:^7.5.3"
+ checksum: 10c0/69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68
+ languageName: node
+ linkType: hard
+
+"make-fetch-happen@npm:^13.0.0":
+ version: 13.0.1
+ resolution: "make-fetch-happen@npm:13.0.1"
+ dependencies:
+ "@npmcli/agent": "npm:^2.0.0"
+ cacache: "npm:^18.0.0"
+ http-cache-semantics: "npm:^4.1.1"
+ is-lambda: "npm:^1.0.1"
+ minipass: "npm:^7.0.2"
+ minipass-fetch: "npm:^3.0.0"
+ minipass-flush: "npm:^1.0.5"
+ minipass-pipeline: "npm:^1.2.4"
+ negotiator: "npm:^0.6.3"
+ proc-log: "npm:^4.2.0"
+ promise-retry: "npm:^2.0.1"
+ ssri: "npm:^10.0.0"
+ checksum: 10c0/df5f4dbb6d98153b751bccf4dc4cc500de85a96a9331db9805596c46aa9f99d9555983954e6c1266d9f981ae37a9e4647f42b9a4bb5466f867f4012e582c9e7e
+ languageName: node
+ linkType: hard
+
+"markdown-it@npm:14.1.0":
+ version: 14.1.0
+ resolution: "markdown-it@npm:14.1.0"
+ dependencies:
+ argparse: "npm:^2.0.1"
+ entities: "npm:^4.4.0"
+ linkify-it: "npm:^5.0.0"
+ mdurl: "npm:^2.0.0"
+ punycode.js: "npm:^2.3.1"
+ uc.micro: "npm:^2.1.0"
+ bin:
+ markdown-it: bin/markdown-it.mjs
+ checksum: 10c0/9a6bb444181d2db7016a4173ae56a95a62c84d4cbfb6916a399b11d3e6581bf1cc2e4e1d07a2f022ae72c25f56db90fbe1e529fca16fbf9541659dc53480d4b4
+ languageName: node
+ linkType: hard
+
+"markdown-table@npm:^3.0.3":
+ version: 3.0.4
+ resolution: "markdown-table@npm:3.0.4"
+ checksum: 10c0/1257b31827629a54c24a5030a3dac952256c559174c95ce3ef89bebd6bff0cb1444b1fd667b1a1bb53307f83278111505b3e26f0c4e7b731e0060d435d2d930b
+ languageName: node
+ linkType: hard
+
+"markdownlint-cli2-formatter-default@npm:0.0.5":
+ version: 0.0.5
+ resolution: "markdownlint-cli2-formatter-default@npm:0.0.5"
+ peerDependencies:
+ markdownlint-cli2: ">=0.0.4"
+ checksum: 10c0/7041a5833846d895054cf273c8e75efc13a03bbc88679cd48ea77240318232e883846037e984358a3ad3825fbb602d83492417ed6e36051bc5b603c4bedb3622
+ languageName: node
+ linkType: hard
+
+"markdownlint-cli2@npm:^0.15.0":
+ version: 0.15.0
+ resolution: "markdownlint-cli2@npm:0.15.0"
+ dependencies:
+ globby: "npm:14.0.2"
+ js-yaml: "npm:4.1.0"
+ jsonc-parser: "npm:3.3.1"
+ markdownlint: "npm:0.36.1"
+ markdownlint-cli2-formatter-default: "npm:0.0.5"
+ micromatch: "npm:4.0.8"
+ bin:
+ markdownlint-cli2: markdownlint-cli2.js
+ checksum: 10c0/eb2bb8c855bfaa1cb5bca338ad262a6b7cdcf3f1624d3b5f77af45a7b1a919a4922d3f68be9651b96f301c3f03ebbfe4ce2067d5f7e97fa7644afe099743ddbf
+ languageName: node
+ linkType: hard
+
+"markdownlint-micromark@npm:0.1.12":
+ version: 0.1.12
+ resolution: "markdownlint-micromark@npm:0.1.12"
+ checksum: 10c0/6833c2b9eb6fd63c43dde30aff8bc526cb97638b287535f8277e2c97015602df0670becdece639986dbe3ac2b279d7c1d308c0a65cb5d2aacc331ea768afa86e
+ languageName: node
+ linkType: hard
+
+"markdownlint@npm:0.36.1":
+ version: 0.36.1
+ resolution: "markdownlint@npm:0.36.1"
+ dependencies:
+ markdown-it: "npm:14.1.0"
+ markdownlint-micromark: "npm:0.1.12"
+ checksum: 10c0/1f93a010c5421a9c9cbd51aeb4046c674b4797ef1c6ad55b0344e7a6ecec46dd38d526e623fd6a3d4c486fe594119c5161dad6033b6468f7719d3c69b5d0cea6
+ languageName: node
+ linkType: hard
+
+"mdurl@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdurl@npm:2.0.0"
+ checksum: 10c0/633db522272f75ce4788440669137c77540d74a83e9015666a9557a152c02e245b192edc20bc90ae953bbab727503994a53b236b4d9c99bdaee594d0e7dd2ce0
+ languageName: node
+ linkType: hard
+
+"merge-stream@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "merge-stream@npm:2.0.0"
+ checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5
+ languageName: node
+ linkType: hard
+
+"merge2@npm:^1.3.0, merge2@npm:^1.4.1":
+ version: 1.4.1
+ resolution: "merge2@npm:1.4.1"
+ checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb
+ languageName: node
+ linkType: hard
+
+"micromatch@npm:4.0.8, micromatch@npm:^4.0.4":
+ version: 4.0.8
+ resolution: "micromatch@npm:4.0.8"
+ dependencies:
+ braces: "npm:^3.0.3"
+ picomatch: "npm:^2.3.1"
+ checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8
+ languageName: node
+ linkType: hard
+
+"mimic-fn@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "mimic-fn@npm:4.0.0"
+ checksum: 10c0/de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "minimatch@npm:3.1.2"
+ dependencies:
+ brace-expansion: "npm:^1.1.7"
+ checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^9.0.3, minimatch@npm:^9.0.4, minimatch@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "minimatch@npm:9.0.5"
+ dependencies:
+ brace-expansion: "npm:^2.0.1"
+ checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed
+ languageName: node
+ linkType: hard
+
+"minipass-collect@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "minipass-collect@npm:2.0.1"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e
+ languageName: node
+ linkType: hard
+
+"minipass-fetch@npm:^3.0.0":
+ version: 3.0.5
+ resolution: "minipass-fetch@npm:3.0.5"
+ dependencies:
+ encoding: "npm:^0.1.13"
+ minipass: "npm:^7.0.3"
+ minipass-sized: "npm:^1.0.3"
+ minizlib: "npm:^2.1.2"
+ dependenciesMeta:
+ encoding:
+ optional: true
+ checksum: 10c0/9d702d57f556274286fdd97e406fc38a2f5c8d15e158b498d7393b1105974b21249289ec571fa2b51e038a4872bfc82710111cf75fae98c662f3d6f95e72152b
+ languageName: node
+ linkType: hard
+
+"minipass-flush@npm:^1.0.5":
+ version: 1.0.5
+ resolution: "minipass-flush@npm:1.0.5"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd
+ languageName: node
+ linkType: hard
+
+"minipass-pipeline@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "minipass-pipeline@npm:1.2.4"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2
+ languageName: node
+ linkType: hard
+
+"minipass-sized@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "minipass-sized@npm:1.0.3"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^3.0.0":
+ version: 3.3.6
+ resolution: "minipass@npm:3.3.6"
+ dependencies:
+ yallist: "npm:^4.0.0"
+ checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "minipass@npm:5.0.0"
+ checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2":
+ version: 7.1.2
+ resolution: "minipass@npm:7.1.2"
+ checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557
+ languageName: node
+ linkType: hard
+
+"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2":
+ version: 2.1.2
+ resolution: "minizlib@npm:2.1.2"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ yallist: "npm:^4.0.0"
+ checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78
+ languageName: node
+ linkType: hard
+
+"mkdirp@npm:^1.0.3":
+ version: 1.0.4
+ resolution: "mkdirp@npm:1.0.4"
+ bin:
+ mkdirp: bin/cmd.js
+ checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf
+ languageName: node
+ linkType: hard
+
+"mlly@npm:^1.7.1, mlly@npm:^1.7.2":
+ version: 1.7.2
+ resolution: "mlly@npm:1.7.2"
+ dependencies:
+ acorn: "npm:^8.12.1"
+ pathe: "npm:^1.1.2"
+ pkg-types: "npm:^1.2.0"
+ ufo: "npm:^1.5.4"
+ checksum: 10c0/e5a990b9d895477f3d3dfceec9797e41d6f029ce3b1b2dcf787d4b7500b4caff4b3cdc0ae5cb82c14b469b85209fe3d7368286415c0ca5415b163219fc6b5f21
+ languageName: node
+ linkType: hard
+
+"ms@npm:^2.1.1, ms@npm:^2.1.3":
+ version: 2.1.3
+ resolution: "ms@npm:2.1.3"
+ checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
+ languageName: node
+ linkType: hard
+
+"mz@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "mz@npm:2.7.0"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ object-assign: "npm:^4.0.1"
+ thenify-all: "npm:^1.0.0"
+ checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39
+ languageName: node
+ linkType: hard
+
+"nanoid@npm:^3.3.7":
+ version: 3.3.7
+ resolution: "nanoid@npm:3.3.7"
+ bin:
+ nanoid: bin/nanoid.cjs
+ checksum: 10c0/e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3
+ languageName: node
+ linkType: hard
+
+"natural-compare@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "natural-compare@npm:1.4.0"
+ checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447
+ languageName: node
+ linkType: hard
+
+"negotiator@npm:^0.6.3":
+ version: 0.6.4
+ resolution: "negotiator@npm:0.6.4"
+ checksum: 10c0/3e677139c7fb7628a6f36335bf11a885a62c21d5390204590a1a214a5631fcbe5ea74ef6a610b60afe84b4d975cbe0566a23f20ee17c77c73e74b80032108dea
+ languageName: node
+ linkType: hard
+
+"no-case@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "no-case@npm:3.0.4"
+ dependencies:
+ lower-case: "npm:^2.0.2"
+ tslib: "npm:^2.0.3"
+ checksum: 10c0/8ef545f0b3f8677c848f86ecbd42ca0ff3cd9dd71c158527b344c69ba14710d816d8489c746b6ca225e7b615108938a0bda0a54706f8c255933703ac1cf8e703
+ languageName: node
+ linkType: hard
+
+"node-fetch-native@npm:^1.6.3":
+ version: 1.6.4
+ resolution: "node-fetch-native@npm:1.6.4"
+ checksum: 10c0/78334dc6def5d1d95cfe87b33ac76c4833592c5eb84779ad2b0c23c689f9dd5d1cfc827035ada72d6b8b218f717798968c5a99aeff0a1a8bf06657e80592f9c3
+ languageName: node
+ linkType: hard
+
+"node-gyp@npm:latest":
+ version: 10.2.0
+ resolution: "node-gyp@npm:10.2.0"
+ dependencies:
+ env-paths: "npm:^2.2.0"
+ exponential-backoff: "npm:^3.1.1"
+ glob: "npm:^10.3.10"
+ graceful-fs: "npm:^4.2.6"
+ make-fetch-happen: "npm:^13.0.0"
+ nopt: "npm:^7.0.0"
+ proc-log: "npm:^4.1.0"
+ semver: "npm:^7.3.5"
+ tar: "npm:^6.2.1"
+ which: "npm:^4.0.0"
+ bin:
+ node-gyp: bin/node-gyp.js
+ checksum: 10c0/00630d67dbd09a45aee0a5d55c05e3916ca9e6d427ee4f7bc392d2d3dc5fad7449b21fc098dd38260a53d9dcc9c879b36704a1994235d4707e7271af7e9a835b
+ languageName: node
+ linkType: hard
+
+"nopt@npm:^7.0.0":
+ version: 7.2.1
+ resolution: "nopt@npm:7.2.1"
+ dependencies:
+ abbrev: "npm:^2.0.0"
+ bin:
+ nopt: bin/nopt.js
+ checksum: 10c0/a069c7c736767121242037a22a788863accfa932ab285a1eb569eb8cd534b09d17206f68c37f096ae785647435e0c5a5a0a67b42ec743e481a455e5ae6a6df81
+ languageName: node
+ linkType: hard
+
+"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0":
+ version: 3.0.0
+ resolution: "normalize-path@npm:3.0.0"
+ checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046
+ languageName: node
+ linkType: hard
+
+"npm-run-path@npm:^5.1.0":
+ version: 5.3.0
+ resolution: "npm-run-path@npm:5.3.0"
+ dependencies:
+ path-key: "npm:^4.0.0"
+ checksum: 10c0/124df74820c40c2eb9a8612a254ea1d557ddfab1581c3e751f825e3e366d9f00b0d76a3c94ecd8398e7f3eee193018622677e95816e8491f0797b21e30b2deba
+ languageName: node
+ linkType: hard
+
+"nypm@npm:^0.3.8":
+ version: 0.3.12
+ resolution: "nypm@npm:0.3.12"
+ dependencies:
+ citty: "npm:^0.1.6"
+ consola: "npm:^3.2.3"
+ execa: "npm:^8.0.1"
+ pathe: "npm:^1.1.2"
+ pkg-types: "npm:^1.2.0"
+ ufo: "npm:^1.5.4"
+ bin:
+ nypm: dist/cli.mjs
+ checksum: 10c0/1455abc1521e2d307736ef7c3b79eb4c2ef1fb2e471b90d16a440f2f7863cbcfe40708061015fd7056ebdba48359845192b749882b12a6659798244a5936ece6
+ languageName: node
+ linkType: hard
+
+"object-assign@npm:^4.0.1":
+ version: 4.1.1
+ resolution: "object-assign@npm:4.1.1"
+ checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
+ languageName: node
+ linkType: hard
+
+"ohash@npm:^1.1.3":
+ version: 1.1.4
+ resolution: "ohash@npm:1.1.4"
+ checksum: 10c0/73c3bcab2891ee2155ed62bb4c2906f622bf2204a3c9f4616ada8a6a76276bb6b4b4180eaf273b7c7d6232793e4d79d486aab436ebfc0d06d92a997f07122864
+ languageName: node
+ linkType: hard
+
+"onetime@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "onetime@npm:6.0.0"
+ dependencies:
+ mimic-fn: "npm:^4.0.0"
+ checksum: 10c0/4eef7c6abfef697dd4479345a4100c382d73c149d2d56170a54a07418c50816937ad09500e1ed1e79d235989d073a9bade8557122aee24f0576ecde0f392bb6c
+ languageName: node
+ linkType: hard
+
+"optionator@npm:^0.9.3":
+ version: 0.9.4
+ resolution: "optionator@npm:0.9.4"
+ dependencies:
+ deep-is: "npm:^0.1.3"
+ fast-levenshtein: "npm:^2.0.6"
+ levn: "npm:^0.4.1"
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:^0.4.0"
+ word-wrap: "npm:^1.2.5"
+ checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675
+ languageName: node
+ linkType: hard
+
+"p-limit@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "p-limit@npm:3.1.0"
+ dependencies:
+ yocto-queue: "npm:^0.1.0"
+ checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a
+ languageName: node
+ linkType: hard
+
+"p-locate@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-locate@npm:5.0.0"
+ dependencies:
+ p-limit: "npm:^3.0.2"
+ checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a
+ languageName: node
+ linkType: hard
+
+"p-map@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "p-map@npm:4.0.0"
+ dependencies:
+ aggregate-error: "npm:^3.0.0"
+ checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75
+ languageName: node
+ linkType: hard
+
+"package-json-from-dist@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "package-json-from-dist@npm:1.0.1"
+ checksum: 10c0/62ba2785eb655fec084a257af34dbe24292ab74516d6aecef97ef72d4897310bc6898f6c85b5cd22770eaa1ce60d55a0230e150fb6a966e3ecd6c511e23d164b
+ languageName: node
+ linkType: hard
+
+"parent-module@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "parent-module@npm:1.0.1"
+ dependencies:
+ callsites: "npm:^3.0.0"
+ checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556
+ languageName: node
+ linkType: hard
+
+"parse-json@npm:^5.2.0":
+ version: 5.2.0
+ resolution: "parse-json@npm:5.2.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.0.0"
+ error-ex: "npm:^1.3.1"
+ json-parse-even-better-errors: "npm:^2.3.0"
+ lines-and-columns: "npm:^1.1.6"
+ checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585
+ languageName: node
+ linkType: hard
+
+"path-exists@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-exists@npm:4.0.0"
+ checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b
+ languageName: node
+ linkType: hard
+
+"path-key@npm:^3.1.0":
+ version: 3.1.1
+ resolution: "path-key@npm:3.1.1"
+ checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c
+ languageName: node
+ linkType: hard
+
+"path-key@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-key@npm:4.0.0"
+ checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3
+ languageName: node
+ linkType: hard
+
+"path-parse@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "path-parse@npm:1.0.7"
+ checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1
+ languageName: node
+ linkType: hard
+
+"path-scurry@npm:^1.11.1":
+ version: 1.11.1
+ resolution: "path-scurry@npm:1.11.1"
+ dependencies:
+ lru-cache: "npm:^10.2.0"
+ minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0"
+ checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d
+ languageName: node
+ linkType: hard
+
+"path-type@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-type@npm:4.0.0"
+ checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c
+ languageName: node
+ linkType: hard
+
+"path-type@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "path-type@npm:5.0.0"
+ checksum: 10c0/e8f4b15111bf483900c75609e5e74e3fcb79f2ddb73e41470028fcd3e4b5162ec65da9907be077ee5012c18801ff7fffb35f9f37a077f3f81d85a0b7d6578efd
+ languageName: node
+ linkType: hard
+
+"pathe@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "pathe@npm:1.1.2"
+ checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897
+ languageName: node
+ linkType: hard
+
+"pathval@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "pathval@npm:2.0.0"
+ checksum: 10c0/602e4ee347fba8a599115af2ccd8179836a63c925c23e04bd056d0674a64b39e3a081b643cc7bc0b84390517df2d800a46fcc5598d42c155fe4977095c2f77c5
+ languageName: node
+ linkType: hard
+
+"perfect-debounce@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "perfect-debounce@npm:1.0.0"
+ checksum: 10c0/e2baac416cae046ef1b270812cf9ccfb0f91c04ea36ac7f5b00bc84cb7f41bdbba087c0ab21b4e02a7ef3a1f1f6db399f137cecec46868bd7d8d88c2a9ee431f
+ languageName: node
+ linkType: hard
+
+"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1":
+ version: 2.3.1
+ resolution: "picomatch@npm:2.3.1"
+ checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "picomatch@npm:4.0.2"
+ checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc
+ languageName: node
+ linkType: hard
+
+"pirates@npm:^4.0.1":
+ version: 4.0.6
+ resolution: "pirates@npm:4.0.6"
+ checksum: 10c0/00d5fa51f8dded94d7429700fb91a0c1ead00ae2c7fd27089f0c5b63e6eca36197fe46384631872690a66f390c5e27198e99006ab77ae472692ab9c2ca903f36
+ languageName: node
+ linkType: hard
+
+"pkg-types@npm:^1.2.0":
+ version: 1.2.1
+ resolution: "pkg-types@npm:1.2.1"
+ dependencies:
+ confbox: "npm:^0.1.8"
+ mlly: "npm:^1.7.2"
+ pathe: "npm:^1.1.2"
+ checksum: 10c0/4aef765c039e3ec3ca55171bb8ad776cf060d894c45ddf92b9d680b3fdb1817c8d1c428f74ea6aae144493fa1d6a97df6b8caec6dc31e418f1ce1f728d38014e
+ languageName: node
+ linkType: hard
+
+"postcss-load-config@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "postcss-load-config@npm:6.0.1"
+ dependencies:
+ lilconfig: "npm:^3.1.1"
+ peerDependencies:
+ jiti: ">=1.21.0"
+ postcss: ">=8.0.9"
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ postcss:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ checksum: 10c0/74173a58816dac84e44853f7afbd283f4ef13ca0b6baeba27701214beec33f9e309b128f8102e2b173e8d45ecba45d279a9be94b46bf48d219626aa9b5730848
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.4.43":
+ version: 8.4.49
+ resolution: "postcss@npm:8.4.49"
+ dependencies:
+ nanoid: "npm:^3.3.7"
+ picocolors: "npm:^1.1.1"
+ source-map-js: "npm:^1.2.1"
+ checksum: 10c0/f1b3f17aaf36d136f59ec373459f18129908235e65dbdc3aee5eef8eba0756106f52de5ec4682e29a2eab53eb25170e7e871b3e4b52a8f1de3d344a514306be3
+ languageName: node
+ linkType: hard
+
+"prelude-ls@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "prelude-ls@npm:1.2.1"
+ checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd
+ languageName: node
+ linkType: hard
+
+"pretty-format@npm:^29.7.0":
+ version: 29.7.0
+ resolution: "pretty-format@npm:29.7.0"
+ dependencies:
+ "@jest/schemas": "npm:^29.6.3"
+ ansi-styles: "npm:^5.0.0"
+ react-is: "npm:^18.0.0"
+ checksum: 10c0/edc5ff89f51916f036c62ed433506b55446ff739358de77207e63e88a28ca2894caac6e73dcb68166a606e51c8087d32d400473e6a9fdd2dbe743f46c9c0276f
+ languageName: node
+ linkType: hard
+
+"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "proc-log@npm:4.2.0"
+ checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9
+ languageName: node
+ linkType: hard
+
+"promise-retry@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "promise-retry@npm:2.0.1"
+ dependencies:
+ err-code: "npm:^2.0.2"
+ retry: "npm:^0.12.0"
+ checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96
+ languageName: node
+ linkType: hard
+
+"prompts@npm:^2.4.2":
+ version: 2.4.2
+ resolution: "prompts@npm:2.4.2"
+ dependencies:
+ kleur: "npm:^3.0.3"
+ sisteransi: "npm:^1.0.5"
+ checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4
+ languageName: node
+ linkType: hard
+
+"punycode.js@npm:^2.3.1":
+ version: 2.3.1
+ resolution: "punycode.js@npm:2.3.1"
+ checksum: 10c0/1d12c1c0e06127fa5db56bd7fdf698daf9a78104456a6b67326877afc21feaa821257b171539caedd2f0524027fa38e67b13dd094159c8d70b6d26d2bea4dfdb
+ languageName: node
+ linkType: hard
+
+"punycode@npm:^2.1.0":
+ version: 2.1.1
+ resolution: "punycode@npm:2.1.1"
+ checksum: 10c0/83815ca9b9177f055771f31980cbec7ffaef10257d50a95ab99b4a30f0404846e85fa6887ee1bbc0aaddb7bad6d96e2fa150a016051ff0f6b92be4ad613ddca8
+ languageName: node
+ linkType: hard
+
+"queue-microtask@npm:^1.2.2":
+ version: 1.2.3
+ resolution: "queue-microtask@npm:1.2.3"
+ checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102
+ languageName: node
+ linkType: hard
+
+"rc9@npm:^2.1.2":
+ version: 2.1.2
+ resolution: "rc9@npm:2.1.2"
+ dependencies:
+ defu: "npm:^6.1.4"
+ destr: "npm:^2.0.3"
+ checksum: 10c0/a2ead3b94bf033e35e4ea40d70062a09feddb8f589c3f5a8fe4e9342976974296aee9f6e9e72bd5e78e6ae4b7bc16dc244f63699fd7322c16314e3238db982c9
+ languageName: node
+ linkType: hard
+
+"react-is@npm:^18.0.0":
+ version: 18.3.1
+ resolution: "react-is@npm:18.3.1"
+ checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
+ languageName: node
+ linkType: hard
+
+"readdirp@npm:^4.0.1":
+ version: 4.0.2
+ resolution: "readdirp@npm:4.0.2"
+ checksum: 10c0/a16ecd8ef3286dcd90648c3b103e3826db2b766cdb4a988752c43a83f683d01c7059158d623cbcd8bdfb39e65d302d285be2d208e7d9f34d022d912b929217dd
+ languageName: node
+ linkType: hard
+
+"readdirp@npm:~3.6.0":
+ version: 3.6.0
+ resolution: "readdirp@npm:3.6.0"
+ dependencies:
+ picomatch: "npm:^2.2.1"
+ checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b
+ languageName: node
+ linkType: hard
+
+"require-from-string@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "require-from-string@npm:2.0.2"
+ checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2
+ languageName: node
+ linkType: hard
+
+"resolve-from@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "resolve-from@npm:4.0.0"
+ checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190
+ languageName: node
+ linkType: hard
+
+"resolve-from@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "resolve-from@npm:5.0.0"
+ checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2
+ languageName: node
+ linkType: hard
+
+"resolve-pkg-maps@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "resolve-pkg-maps@npm:1.0.0"
+ checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^1.22.4":
+ version: 1.22.8
+ resolution: "resolve@npm:1.22.8"
+ dependencies:
+ is-core-module: "npm:^2.13.0"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/07e179f4375e1fd072cfb72ad66d78547f86e6196c4014b31cb0b8bb1db5f7ca871f922d08da0fbc05b94e9fd42206f819648fa3b5b873ebbc8e1dc68fec433a
+ languageName: node
+ linkType: hard
+
+"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin":
+ version: 1.22.8
+ resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d"
+ dependencies:
+ is-core-module: "npm:^2.13.0"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/0446f024439cd2e50c6c8fa8ba77eaa8370b4180f401a96abf3d1ebc770ac51c1955e12764cde449fde3fff480a61f84388e3505ecdbab778f4bef5f8212c729
+ languageName: node
+ linkType: hard
+
+"retry@npm:^0.12.0":
+ version: 0.12.0
+ resolution: "retry@npm:0.12.0"
+ checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe
+ languageName: node
+ linkType: hard
+
+"reusify@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "reusify@npm:1.0.4"
+ checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107
+ languageName: node
+ linkType: hard
+
+"rollup@npm:^4.20.0, rollup@npm:^4.24.0":
+ version: 4.28.0
+ resolution: "rollup@npm:4.28.0"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.28.0"
+ "@rollup/rollup-android-arm64": "npm:4.28.0"
+ "@rollup/rollup-darwin-arm64": "npm:4.28.0"
+ "@rollup/rollup-darwin-x64": "npm:4.28.0"
+ "@rollup/rollup-freebsd-arm64": "npm:4.28.0"
+ "@rollup/rollup-freebsd-x64": "npm:4.28.0"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.28.0"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.28.0"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.28.0"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.28.0"
+ "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.28.0"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.28.0"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.28.0"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.28.0"
+ "@rollup/rollup-linux-x64-musl": "npm:4.28.0"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.28.0"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.28.0"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.28.0"
+ "@types/estree": "npm:1.0.6"
+ fsevents: "npm:~2.3.2"
+ dependenciesMeta:
+ "@rollup/rollup-android-arm-eabi":
+ optional: true
+ "@rollup/rollup-android-arm64":
+ optional: true
+ "@rollup/rollup-darwin-arm64":
+ optional: true
+ "@rollup/rollup-darwin-x64":
+ optional: true
+ "@rollup/rollup-freebsd-arm64":
+ optional: true
+ "@rollup/rollup-freebsd-x64":
+ optional: true
+ "@rollup/rollup-linux-arm-gnueabihf":
+ optional: true
+ "@rollup/rollup-linux-arm-musleabihf":
+ optional: true
+ "@rollup/rollup-linux-arm64-gnu":
+ optional: true
+ "@rollup/rollup-linux-arm64-musl":
+ optional: true
+ "@rollup/rollup-linux-powerpc64le-gnu":
+ optional: true
+ "@rollup/rollup-linux-riscv64-gnu":
+ optional: true
+ "@rollup/rollup-linux-s390x-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-musl":
+ optional: true
+ "@rollup/rollup-win32-arm64-msvc":
+ optional: true
+ "@rollup/rollup-win32-ia32-msvc":
+ optional: true
+ "@rollup/rollup-win32-x64-msvc":
+ optional: true
+ fsevents:
+ optional: true
+ bin:
+ rollup: dist/bin/rollup
+ checksum: 10c0/98d3bc2b784eff71b997cfc2be97c00e2f100ee38adc2f8ada7b9b9ecbbc96937f667a6a247a45491807b3f2adef3c73d1f5df40d71771bff0c2d8c0cca9b369
+ languageName: node
+ linkType: hard
+
+"run-parallel@npm:^1.1.9":
+ version: 1.2.0
+ resolution: "run-parallel@npm:1.2.0"
+ dependencies:
+ queue-microtask: "npm:^1.2.2"
+ checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39
+ languageName: node
+ linkType: hard
+
+"rxjs@npm:^7.8.1":
+ version: 7.8.1
+ resolution: "rxjs@npm:7.8.1"
+ dependencies:
+ tslib: "npm:^2.1.0"
+ checksum: 10c0/3c49c1ecd66170b175c9cacf5cef67f8914dcbc7cd0162855538d365c83fea631167cacb644b3ce533b2ea0e9a4d0b12175186985f89d75abe73dbd8f7f06f68
+ languageName: node
+ linkType: hard
+
+"safer-buffer@npm:>= 2.1.2 < 3.0.0":
+ version: 2.1.2
+ resolution: "safer-buffer@npm:2.1.2"
+ checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4
+ languageName: node
+ linkType: hard
+
+"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3":
+ version: 7.6.3
+ resolution: "semver@npm:7.6.3"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf
+ languageName: node
+ linkType: hard
+
+"shebang-command@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "shebang-command@npm:2.0.0"
+ dependencies:
+ shebang-regex: "npm:^3.0.0"
+ checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e
+ languageName: node
+ linkType: hard
+
+"shebang-regex@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "shebang-regex@npm:3.0.0"
+ checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690
+ languageName: node
+ linkType: hard
+
+"siginfo@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "siginfo@npm:2.0.0"
+ checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34
+ languageName: node
+ linkType: hard
+
+"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "signal-exit@npm:4.1.0"
+ checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83
+ languageName: node
+ linkType: hard
+
+"sisteransi@npm:^1.0.5":
+ version: 1.0.5
+ resolution: "sisteransi@npm:1.0.5"
+ checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46
+ languageName: node
+ linkType: hard
+
+"slash@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "slash@npm:3.0.0"
+ checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b
+ languageName: node
+ linkType: hard
+
+"slash@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "slash@npm:5.1.0"
+ checksum: 10c0/eb48b815caf0bdc390d0519d41b9e0556a14380f6799c72ba35caf03544d501d18befdeeef074bc9c052acf69654bc9e0d79d7f1de0866284137a40805299eb3
+ languageName: node
+ linkType: hard
+
+"smart-buffer@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "smart-buffer@npm:4.2.0"
+ checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539
+ languageName: node
+ linkType: hard
+
+"socks-proxy-agent@npm:^8.0.3":
+ version: 8.0.4
+ resolution: "socks-proxy-agent@npm:8.0.4"
+ dependencies:
+ agent-base: "npm:^7.1.1"
+ debug: "npm:^4.3.4"
+ socks: "npm:^2.8.3"
+ checksum: 10c0/345593bb21b95b0508e63e703c84da11549f0a2657d6b4e3ee3612c312cb3a907eac10e53b23ede3557c6601d63252103494caa306b66560f43af7b98f53957a
+ languageName: node
+ linkType: hard
+
+"socks@npm:^2.8.3":
+ version: 2.8.3
+ resolution: "socks@npm:2.8.3"
+ dependencies:
+ ip-address: "npm:^9.0.5"
+ smart-buffer: "npm:^4.2.0"
+ checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7
+ languageName: node
+ linkType: hard
+
+"source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "source-map-js@npm:1.2.1"
+ checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
+ languageName: node
+ linkType: hard
+
+"source-map@npm:0.8.0-beta.0":
+ version: 0.8.0-beta.0
+ resolution: "source-map@npm:0.8.0-beta.0"
+ dependencies:
+ whatwg-url: "npm:^7.0.0"
+ checksum: 10c0/fb4d9bde9a9fdb2c29b10e5eae6c71d10e09ef467e1afb75fdec2eb7e11fa5b343a2af553f74f18b695dbc0b81f9da2e9fa3d7a317d5985e9939499ec6087835
+ languageName: node
+ linkType: hard
+
+"sprintf-js@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "sprintf-js@npm:1.1.3"
+ checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec
+ languageName: node
+ linkType: hard
+
+"ssri@npm:^10.0.0":
+ version: 10.0.6
+ resolution: "ssri@npm:10.0.6"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/e5a1e23a4057a86a97971465418f22ea89bd439ac36ade88812dd920e4e61873e8abd6a9b72a03a67ef50faa00a2daf1ab745c5a15b46d03e0544a0296354227
+ languageName: node
+ linkType: hard
+
+"stable-hash@npm:^0.0.4":
+ version: 0.0.4
+ resolution: "stable-hash@npm:0.0.4"
+ checksum: 10c0/53d010d2a1b014fb60d398c095f43912c353b7b44774e55222bb26fd428bc75b73d7bdfcae509ce927c23ca9c5aff2dc1bc82f191d30e57a879550bc2952bdb0
+ languageName: node
+ linkType: hard
+
+"stackback@npm:0.0.2":
+ version: 0.0.2
+ resolution: "stackback@npm:0.0.2"
+ checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983
+ languageName: node
+ linkType: hard
+
+"std-env@npm:^3.8.0":
+ version: 3.8.0
+ resolution: "std-env@npm:3.8.0"
+ checksum: 10c0/f560a2902fd0fa3d648d7d0acecbd19d664006f7372c1fba197ed4c216b4c9e48db6e2769b5fe1616d42a9333c9f066c5011935035e85c59f45dc4f796272040
+ languageName: node
+ linkType: hard
+
+"string-argv@npm:^0.3.1":
+ version: 0.3.2
+ resolution: "string-argv@npm:0.3.2"
+ checksum: 10c0/75c02a83759ad1722e040b86823909d9a2fc75d15dd71ec4b537c3560746e33b5f5a07f7332d1e3f88319909f82190843aa2f0a0d8c8d591ec08e93d5b8dec82
+ languageName: node
+ linkType: hard
+
+"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0":
+ version: 4.2.3
+ resolution: "string-width@npm:4.2.3"
+ dependencies:
+ emoji-regex: "npm:^8.0.0"
+ is-fullwidth-code-point: "npm:^3.0.0"
+ strip-ansi: "npm:^6.0.1"
+ checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b
+ languageName: node
+ linkType: hard
+
+"string-width@npm:^5.0.1, string-width@npm:^5.1.2":
+ version: 5.1.2
+ resolution: "string-width@npm:5.1.2"
+ dependencies:
+ eastasianwidth: "npm:^0.2.0"
+ emoji-regex: "npm:^9.2.2"
+ strip-ansi: "npm:^7.0.1"
+ checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca
+ languageName: node
+ linkType: hard
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "strip-ansi@npm:6.0.1"
+ dependencies:
+ ansi-regex: "npm:^5.0.1"
+ checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952
+ languageName: node
+ linkType: hard
+
+"strip-ansi@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "strip-ansi@npm:7.0.1"
+ dependencies:
+ ansi-regex: "npm:^6.0.1"
+ checksum: 10c0/a94805f54caefae6cf4870ee6acfe50cff69d90a37994bf02c096042d9939ee211e1568f34b9fa5efa03c7d7fea79cb3ac8a4e517ceb848284ae300da06ca7e9
+ languageName: node
+ linkType: hard
+
+"strip-final-newline@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "strip-final-newline@npm:3.0.0"
+ checksum: 10c0/a771a17901427bac6293fd416db7577e2bc1c34a19d38351e9d5478c3c415f523f391003b42ed475f27e33a78233035df183525395f731d3bfb8cdcbd4da08ce
+ languageName: node
+ linkType: hard
+
+"strip-json-comments@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "strip-json-comments@npm:3.1.1"
+ checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd
+ languageName: node
+ linkType: hard
+
+"sucrase@npm:^3.35.0":
+ version: 3.35.0
+ resolution: "sucrase@npm:3.35.0"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.2"
+ commander: "npm:^4.0.0"
+ glob: "npm:^10.3.10"
+ lines-and-columns: "npm:^1.1.6"
+ mz: "npm:^2.7.0"
+ pirates: "npm:^4.0.1"
+ ts-interface-checker: "npm:^0.1.9"
+ bin:
+ sucrase: bin/sucrase
+ sucrase-node: bin/sucrase-node
+ checksum: 10c0/ac85f3359d2c2ecbf5febca6a24ae9bf96c931f05fde533c22a94f59c6a74895e5d5f0e871878dfd59c2697a75ebb04e4b2224ef0bfc24ca1210735c2ec191ef
+ languageName: node
+ linkType: hard
+
+"supports-color@npm:^7.1.0":
+ version: 7.2.0
+ resolution: "supports-color@npm:7.2.0"
+ dependencies:
+ has-flag: "npm:^4.0.0"
+ checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124
+ languageName: node
+ linkType: hard
+
+"supports-preserve-symlinks-flag@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
+ checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39
+ languageName: node
+ linkType: hard
+
+"tapable@npm:^2.2.0":
+ version: 2.2.1
+ resolution: "tapable@npm:2.2.1"
+ checksum: 10c0/bc40e6efe1e554d075469cedaba69a30eeb373552aaf41caeaaa45bf56ffacc2674261b106245bd566b35d8f3329b52d838e851ee0a852120acae26e622925c9
+ languageName: node
+ linkType: hard
+
+"tar@npm:^6.1.11, tar@npm:^6.2.0, tar@npm:^6.2.1":
+ version: 6.2.1
+ resolution: "tar@npm:6.2.1"
+ dependencies:
+ chownr: "npm:^2.0.0"
+ fs-minipass: "npm:^2.0.0"
+ minipass: "npm:^5.0.0"
+ minizlib: "npm:^2.1.1"
+ mkdirp: "npm:^1.0.3"
+ yallist: "npm:^4.0.0"
+ checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537
+ languageName: node
+ linkType: hard
+
+"test-exclude@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "test-exclude@npm:7.0.1"
+ dependencies:
+ "@istanbuljs/schema": "npm:^0.1.2"
+ glob: "npm:^10.4.1"
+ minimatch: "npm:^9.0.4"
+ checksum: 10c0/6d67b9af4336a2e12b26a68c83308c7863534c65f27ed4ff7068a56f5a58f7ac703e8fc80f698a19bb154fd8f705cdf7ec347d9512b2c522c737269507e7b263
+ languageName: node
+ linkType: hard
+
+"thenify-all@npm:^1.0.0":
+ version: 1.6.0
+ resolution: "thenify-all@npm:1.6.0"
+ dependencies:
+ thenify: "npm:>= 3.1.0 < 4"
+ checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b
+ languageName: node
+ linkType: hard
+
+"thenify@npm:>= 3.1.0 < 4":
+ version: 3.3.1
+ resolution: "thenify@npm:3.3.1"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767
+ languageName: node
+ linkType: hard
+
+"tinybench@npm:^2.9.0":
+ version: 2.9.0
+ resolution: "tinybench@npm:2.9.0"
+ checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c
+ languageName: node
+ linkType: hard
+
+"tinyexec@npm:^0.3.1":
+ version: 0.3.1
+ resolution: "tinyexec@npm:0.3.1"
+ checksum: 10c0/11e7a7c5d8b3bddf8b5cbe82a9290d70a6fad84d528421d5d18297f165723cb53d2e737d8f58dcce5ca56f2e4aa2d060f02510b1f8971784f97eb3e9aec28f09
+ languageName: node
+ linkType: hard
+
+"tinyglobby@npm:^0.2.10, tinyglobby@npm:^0.2.9":
+ version: 0.2.10
+ resolution: "tinyglobby@npm:0.2.10"
+ dependencies:
+ fdir: "npm:^6.4.2"
+ picomatch: "npm:^4.0.2"
+ checksum: 10c0/ce946135d39b8c0e394e488ad59f4092e8c4ecd675ef1bcd4585c47de1b325e61ec6adfbfbe20c3c2bfa6fd674c5b06de2a2e65c433f752ae170aff11793e5ef
+ languageName: node
+ linkType: hard
+
+"tinypool@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "tinypool@npm:1.0.1"
+ checksum: 10c0/90939d6a03f1519c61007bf416632dc1f0b9c1a9dd673c179ccd9e36a408437384f984fc86555a5d040d45b595abc299c3bb39d354439e98a090766b5952e73d
+ languageName: node
+ linkType: hard
+
+"tinyrainbow@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "tinyrainbow@npm:1.2.0"
+ checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192
+ languageName: node
+ linkType: hard
+
+"tinyspy@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "tinyspy@npm:3.0.2"
+ checksum: 10c0/55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0
+ languageName: node
+ linkType: hard
+
+"to-regex-range@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "to-regex-range@npm:5.0.1"
+ dependencies:
+ is-number: "npm:^7.0.0"
+ checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892
+ languageName: node
+ linkType: hard
+
+"tr46@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "tr46@npm:1.0.1"
+ dependencies:
+ punycode: "npm:^2.1.0"
+ checksum: 10c0/41525c2ccce86e3ef30af6fa5e1464e6d8bb4286a58ea8db09228f598889581ef62347153f6636cd41553dc41685bdfad0a9d032ef58df9fbb0792b3447d0f04
+ languageName: node
+ linkType: hard
+
+"tree-kill@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "tree-kill@npm:1.2.2"
+ bin:
+ tree-kill: cli.js
+ checksum: 10c0/7b1b7c7f17608a8f8d20a162e7957ac1ef6cd1636db1aba92f4e072dc31818c2ff0efac1e3d91064ede67ed5dc57c565420531a8134090a12ac10cf792ab14d2
+ languageName: node
+ linkType: hard
+
+"ts-api-utils@npm:^1.3.0":
+ version: 1.4.0
+ resolution: "ts-api-utils@npm:1.4.0"
+ peerDependencies:
+ typescript: ">=4.2.0"
+ checksum: 10c0/1b2bfa50ea52771d564bb143bb69010d25cda03ed573095fbac9b86f717012426443af6647e00e3db70fca60360482a30c1be7cf73c3521c321f6bf5e3594ea0
+ languageName: node
+ linkType: hard
+
+"ts-interface-checker@npm:^0.1.9":
+ version: 0.1.13
+ resolution: "ts-interface-checker@npm:0.1.13"
+ checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7
+ languageName: node
+ linkType: hard
+
+"tslib@npm:^1.8.1":
+ version: 1.14.1
+ resolution: "tslib@npm:1.14.1"
+ checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2
+ languageName: node
+ linkType: hard
+
+"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.6.3":
+ version: 2.8.1
+ resolution: "tslib@npm:2.8.1"
+ checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
+ languageName: node
+ linkType: hard
+
+"tsup@npm:^8.3.5":
+ version: 8.3.5
+ resolution: "tsup@npm:8.3.5"
+ dependencies:
+ bundle-require: "npm:^5.0.0"
+ cac: "npm:^6.7.14"
+ chokidar: "npm:^4.0.1"
+ consola: "npm:^3.2.3"
+ debug: "npm:^4.3.7"
+ esbuild: "npm:^0.24.0"
+ joycon: "npm:^3.1.1"
+ picocolors: "npm:^1.1.1"
+ postcss-load-config: "npm:^6.0.1"
+ resolve-from: "npm:^5.0.0"
+ rollup: "npm:^4.24.0"
+ source-map: "npm:0.8.0-beta.0"
+ sucrase: "npm:^3.35.0"
+ tinyexec: "npm:^0.3.1"
+ tinyglobby: "npm:^0.2.9"
+ tree-kill: "npm:^1.2.2"
+ peerDependencies:
+ "@microsoft/api-extractor": ^7.36.0
+ "@swc/core": ^1
+ postcss: ^8.4.12
+ typescript: ">=4.5.0"
+ peerDependenciesMeta:
+ "@microsoft/api-extractor":
+ optional: true
+ "@swc/core":
+ optional: true
+ postcss:
+ optional: true
+ typescript:
+ optional: true
+ bin:
+ tsup: dist/cli-default.js
+ tsup-node: dist/cli-node.js
+ checksum: 10c0/7794953cbc784b7c8f14c4898d36a293b815b528d3098c2416aeaa2b4775dc477132cd12f75f6d32737dfd15ba10139c73f7039045352f2ba1ea7e5fe6fe3773
+ languageName: node
+ linkType: hard
+
+"tsutils@npm:^3.21.0":
+ version: 3.21.0
+ resolution: "tsutils@npm:3.21.0"
+ dependencies:
+ tslib: "npm:^1.8.1"
+ peerDependencies:
+ typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2
+ languageName: node
+ linkType: hard
+
+"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
+ version: 0.4.0
+ resolution: "type-check@npm:0.4.0"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58
+ languageName: node
+ linkType: hard
+
+"type-detect@npm:^4.0.8":
+ version: 4.1.0
+ resolution: "type-detect@npm:4.1.0"
+ checksum: 10c0/df8157ca3f5d311edc22885abc134e18ff8ffbc93d6a9848af5b682730ca6a5a44499259750197250479c5331a8a75b5537529df5ec410622041650a7f293e2a
+ languageName: node
+ linkType: hard
+
+"type-fest@npm:^2.11.2":
+ version: 2.19.0
+ resolution: "type-fest@npm:2.19.0"
+ checksum: 10c0/a5a7ecf2e654251613218c215c7493574594951c08e52ab9881c9df6a6da0aeca7528c213c622bc374b4e0cb5c443aa3ab758da4e3c959783ce884c3194e12cb
+ languageName: node
+ linkType: hard
+
+"type-fest@npm:^3.0.0":
+ version: 3.13.1
+ resolution: "type-fest@npm:3.13.1"
+ checksum: 10c0/547d22186f73a8c04590b70dcf63baff390078c75ea8acd366bbd510fd0646e348bd1970e47ecf795b7cff0b41d26e9c475c1fedd6ef5c45c82075fbf916b629
+ languageName: node
+ linkType: hard
+
+"typescript-eslint@npm:^8.17.0":
+ version: 8.17.0
+ resolution: "typescript-eslint@npm:8.17.0"
+ dependencies:
+ "@typescript-eslint/eslint-plugin": "npm:8.17.0"
+ "@typescript-eslint/parser": "npm:8.17.0"
+ "@typescript-eslint/utils": "npm:8.17.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/b148525769b9afa789ad3c2d52249fa78e67a225d48d17f2f0117b0e8b52566112be3a35de6cd26bcaffba3114be87c1070f7f4b4e2b730c059668fec4a530bc
+ languageName: node
+ linkType: hard
+
+"typescript@npm:~5.7.2":
+ version: 5.7.2
+ resolution: "typescript@npm:5.7.2"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622
+ languageName: node
+ linkType: hard
+
+"typescript@patch:typescript@npm%3A~5.7.2#optional!builtin":
+ version: 5.7.2
+ resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5786d5"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/f3b8082c9d1d1629a215245c9087df56cb784f9fb6f27b5d55577a20e68afe2a889c040aacff6d27e35be165ecf9dca66e694c42eb9a50b3b2c451b36b5675cb
+ languageName: node
+ linkType: hard
+
+"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "uc.micro@npm:2.1.0"
+ checksum: 10c0/8862eddb412dda76f15db8ad1c640ccc2f47cdf8252a4a30be908d535602c8d33f9855dfcccb8b8837855c1ce1eaa563f7fa7ebe3c98fd0794351aab9b9c55fa
+ languageName: node
+ linkType: hard
+
+"ufo@npm:^1.5.4":
+ version: 1.5.4
+ resolution: "ufo@npm:1.5.4"
+ checksum: 10c0/b5dc4dc435c49c9ef8890f1b280a19ee4d0954d1d6f9ab66ce62ce64dd04c7be476781531f952a07c678d51638d02ad4b98e16237be29149295b0f7c09cda765
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:~5.26.4":
+ version: 5.26.5
+ resolution: "undici-types@npm:5.26.5"
+ checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501
+ languageName: node
+ linkType: hard
+
+"unicorn-magic@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "unicorn-magic@npm:0.1.0"
+ checksum: 10c0/e4ed0de05b0a05e735c7d8a2930881e5efcfc3ec897204d5d33e7e6247f4c31eac92e383a15d9a6bccb7319b4271ee4bea946e211bf14951fec6ff2cbbb66a92
+ languageName: node
+ linkType: hard
+
+"unique-filename@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "unique-filename@npm:3.0.0"
+ dependencies:
+ unique-slug: "npm:^4.0.0"
+ checksum: 10c0/6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f
+ languageName: node
+ linkType: hard
+
+"unique-slug@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "unique-slug@npm:4.0.0"
+ dependencies:
+ imurmurhash: "npm:^0.1.4"
+ checksum: 10c0/cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635
+ languageName: node
+ linkType: hard
+
+"uri-js@npm:^4.2.2":
+ version: 4.4.1
+ resolution: "uri-js@npm:4.4.1"
+ dependencies:
+ punycode: "npm:^2.1.0"
+ checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c
+ languageName: node
+ linkType: hard
+
+"vite-node@npm:2.1.8":
+ version: 2.1.8
+ resolution: "vite-node@npm:2.1.8"
+ dependencies:
+ cac: "npm:^6.7.14"
+ debug: "npm:^4.3.7"
+ es-module-lexer: "npm:^1.5.4"
+ pathe: "npm:^1.1.2"
+ vite: "npm:^5.0.0"
+ bin:
+ vite-node: vite-node.mjs
+ checksum: 10c0/cb28027a7425ba29780e216164c07d36a4ff9eb60d83afcad3bc222fd5a5f3e36030071c819edd6d910940f502d49e52f7564743617bc1c5875485b0952c72d5
+ languageName: node
+ linkType: hard
+
+"vite@npm:^5.0.0":
+ version: 5.4.11
+ resolution: "vite@npm:5.4.11"
+ dependencies:
+ esbuild: "npm:^0.21.3"
+ fsevents: "npm:~2.3.3"
+ postcss: "npm:^8.4.43"
+ rollup: "npm:^4.20.0"
+ peerDependencies:
+ "@types/node": ^18.0.0 || >=20.0.0
+ less: "*"
+ lightningcss: ^1.21.0
+ sass: "*"
+ sass-embedded: "*"
+ stylus: "*"
+ sugarss: "*"
+ terser: ^5.4.0
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/d536bb7af57dd0eca2a808f95f5ff1d7b7ffb8d86e17c6893087680a0448bd0d15e07475270c8a6de65cb5115592d037130a1dd979dc76bcef8c1dda202a1874
+ languageName: node
+ linkType: hard
+
+"vitest@npm:^2.1.8":
+ version: 2.1.8
+ resolution: "vitest@npm:2.1.8"
+ dependencies:
+ "@vitest/expect": "npm:2.1.8"
+ "@vitest/mocker": "npm:2.1.8"
+ "@vitest/pretty-format": "npm:^2.1.8"
+ "@vitest/runner": "npm:2.1.8"
+ "@vitest/snapshot": "npm:2.1.8"
+ "@vitest/spy": "npm:2.1.8"
+ "@vitest/utils": "npm:2.1.8"
+ chai: "npm:^5.1.2"
+ debug: "npm:^4.3.7"
+ expect-type: "npm:^1.1.0"
+ magic-string: "npm:^0.30.12"
+ pathe: "npm:^1.1.2"
+ std-env: "npm:^3.8.0"
+ tinybench: "npm:^2.9.0"
+ tinyexec: "npm:^0.3.1"
+ tinypool: "npm:^1.0.1"
+ tinyrainbow: "npm:^1.2.0"
+ vite: "npm:^5.0.0"
+ vite-node: "npm:2.1.8"
+ why-is-node-running: "npm:^2.3.0"
+ peerDependencies:
+ "@edge-runtime/vm": "*"
+ "@types/node": ^18.0.0 || >=20.0.0
+ "@vitest/browser": 2.1.8
+ "@vitest/ui": 2.1.8
+ happy-dom: "*"
+ jsdom: "*"
+ peerDependenciesMeta:
+ "@edge-runtime/vm":
+ optional: true
+ "@types/node":
+ optional: true
+ "@vitest/browser":
+ optional: true
+ "@vitest/ui":
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ bin:
+ vitest: vitest.mjs
+ checksum: 10c0/e70631bad5662d6c60c5cf836a4baf58b890db6654fef1f608fe6a86aa49a2b9f078aac74b719d4d3c87c5c781968cc73590a7935277b48f3d8b6fb9c5b4d276
+ languageName: node
+ linkType: hard
+
+"webidl-conversions@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "webidl-conversions@npm:4.0.2"
+ checksum: 10c0/def5c5ac3479286dffcb604547628b2e6b46c5c5b8a8cfaa8c71dc3bafc85859bde5fbe89467ff861f571ab38987cf6ab3d6e7c80b39b999e50e803c12f3164f
+ languageName: node
+ linkType: hard
+
+"whatwg-url@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "whatwg-url@npm:7.1.0"
+ dependencies:
+ lodash.sortby: "npm:^4.7.0"
+ tr46: "npm:^1.0.1"
+ webidl-conversions: "npm:^4.0.2"
+ checksum: 10c0/2785fe4647690e5a0225a79509ba5e21fdf4a71f9de3eabdba1192483fe006fc79961198e0b99f82751557309f17fc5a07d4d83c251aa5b2f85ba71e674cbee9
+ languageName: node
+ linkType: hard
+
+"which@npm:^2.0.1":
+ version: 2.0.2
+ resolution: "which@npm:2.0.2"
+ dependencies:
+ isexe: "npm:^2.0.0"
+ bin:
+ node-which: ./bin/node-which
+ checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f
+ languageName: node
+ linkType: hard
+
+"which@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "which@npm:4.0.0"
+ dependencies:
+ isexe: "npm:^3.1.1"
+ bin:
+ node-which: bin/which.js
+ checksum: 10c0/449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a
+ languageName: node
+ linkType: hard
+
+"why-is-node-running@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "why-is-node-running@npm:2.3.0"
+ dependencies:
+ siginfo: "npm:^2.0.0"
+ stackback: "npm:0.0.2"
+ bin:
+ why-is-node-running: cli.js
+ checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054
+ languageName: node
+ linkType: hard
+
+"word-wrap@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "word-wrap@npm:1.2.5"
+ checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20
+ languageName: node
+ linkType: hard
+
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version: 7.0.0
+ resolution: "wrap-ansi@npm:7.0.0"
+ dependencies:
+ ansi-styles: "npm:^4.0.0"
+ string-width: "npm:^4.1.0"
+ strip-ansi: "npm:^6.0.0"
+ checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da
+ languageName: node
+ linkType: hard
+
+"wrap-ansi@npm:^8.1.0":
+ version: 8.1.0
+ resolution: "wrap-ansi@npm:8.1.0"
+ dependencies:
+ ansi-styles: "npm:^6.1.0"
+ string-width: "npm:^5.0.1"
+ strip-ansi: "npm:^7.0.1"
+ checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "yallist@npm:4.0.0"
+ checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a
+ languageName: node
+ linkType: hard
+
+"yocto-queue@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "yocto-queue@npm:0.1.0"
+ checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f
+ languageName: node
+ linkType: hard